From bdfa401de267331f4c691b0d51362b25e29fd364 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=A4=95=E0=A4=BE=E0=A4=B0=E0=A4=A4=E0=A5=8B=E0=A4=AB?= =?UTF-8?q?=E0=A5=8D=E0=A4=AB=E0=A5=87=E0=A4=B2=E0=A4=B8=E0=A5=8D=E0=A4=95?= =?UTF-8?q?=E0=A5=8D=E0=A4=B0=E0=A4=BF=E0=A4=AA=E0=A5=8D=E0=A4=9F=E2=84=A2?= Date: Wed, 25 May 2022 19:40:51 +0200 Subject: [PATCH 001/609] Add Docker Compose example for MariaDB --- docker/compose/withMariaDB/.env | 8 ++++ docker/compose/withMariaDB/README.md | 26 +++++++++++ docker/compose/withMariaDB/docker-compose.yml | 43 +++++++++++++++++++ 3 files changed, 77 insertions(+) create mode 100644 docker/compose/withMariaDB/.env create mode 100644 docker/compose/withMariaDB/README.md create mode 100644 docker/compose/withMariaDB/docker-compose.yml diff --git a/docker/compose/withMariaDB/.env b/docker/compose/withMariaDB/.env new file mode 100644 index 00000000000..48f9efcd642 --- /dev/null +++ b/docker/compose/withMariaDB/.env @@ -0,0 +1,8 @@ +MARIADB_ROOT_PASSWORD=changePassword + +MARIADB_DATABASE=n8n +MARIADB_USER=changeUser +MARIADB_PASSWORD=changePassword + +N8N_BASIC_AUTH_USER=changeUser +N8N_BASIC_AUTH_PASSWORD=changePassword diff --git a/docker/compose/withMariaDB/README.md b/docker/compose/withMariaDB/README.md new file mode 100644 index 00000000000..0cc6dff0ebe --- /dev/null +++ b/docker/compose/withMariaDB/README.md @@ -0,0 +1,26 @@ +# n8n with MariaDB + +Starts n8n with MariaDB as database. + + +## Start + +To start n8n with MariaDB simply start docker-compose by executing the following +command in the current folder. + + +**IMPORTANT:** But before you do that change the default users and passwords in the [`.env`](.env) file! + +``` +docker-compose up -d +``` + +To stop it execute: + +``` +docker-compose stop +``` + +## Configuration + +The default name of the database, user and password for MariaDB can be changed in the [`.env`](.env) file in the current directory. diff --git a/docker/compose/withMariaDB/docker-compose.yml b/docker/compose/withMariaDB/docker-compose.yml new file mode 100644 index 00000000000..e1c6d0d8479 --- /dev/null +++ b/docker/compose/withMariaDB/docker-compose.yml @@ -0,0 +1,43 @@ +version: '3.8' + +volumes: + db_storage: + n8n_storage: + +services: + db: + image: mariadb:10.7 + restart: always + environment: + - MARIADB_ROOT_PASSWORD + - MARIADB_DATABASE + - MARIADB_USER + - MARIADB_PASSWORD + - MARIADB_MYSQL_LOCALHOST_USER=true + volumes: + - db_storage:/var/lib/mysql + healthcheck: + test: "/usr/bin/mysql --user=${MARIADB_USER} --password=${MARIADB_PASSWORD} --execute 'SELECT 1;'" + interval: 10s + timeout: 5s + retries: 10 + + n8n: + image: n8nio/n8n + restart: always + environment: + - DB_TYPE=mariadb + - DB_MYSQLDB_HOST=db + - DB_MYSQLDB_DATABASE=${MARIADB_DATABASE} + - DB_MYSQLDB_USER=${MARIADB_USER} + - DB_MYSQLDB_PASSWORD=${MARIADB_PASSWORD} + ports: + - 5678:5678 + links: + - db + volumes: + - n8n_storage:/home/node/ + command: n8n start --tunnel + depends_on: + db: + condition: service_healthy From 577c73ee25c5bfc943ef5ed1de550fcb489f4998 Mon Sep 17 00:00:00 2001 From: Mutasem Aldmour <4711238+mutdmour@users.noreply.github.com> Date: Wed, 20 Jul 2022 13:32:51 +0200 Subject: [PATCH 002/609] feat(editor): Add drag and drop data mapping (#3708) * commit package lock * refactor param options out * use action toggle * handle click on toggle * update color toggle * fix toggle * show options * update expression color * update pointer * fix readonly * fix readonly * fix expression spacing * refactor input label * show icon for headers * center icon * fix multi params * add credential options * increase spacing * update expression view * update transition * update el padding * rename side to options * fix label overflow * fix bug with unnessary lines * add overlay * fix bug affecting other pages * clean up spacing * rename * update icon size * fix toggle in users * clean up func * clean up css * use css var * fix overlay bug * clean up input * clean up input * clean up unnessary css * revert * update quotes * rename method * remove console errors * refactor data table * add drag button * make hoverable cells * add drag hint * disabel for output panel * add drag * disable for readonly * Add dragging * add draggable pill * add mapping targets * remove font color * Transferable * fix linting issue * teleport component * fix line * disable for readonly * fix position of data pill * fix position of data pill * ignore import * add droppable state * remove draggable key * update bg color * add value drop * use direct input * remove transition * add animation * shorten name * handle empty value * fix switch bug * fix up animation * add notification * add hint * add tooltip * show draggable hintm * fix multiple expre * fix hoverable * keep options on focus * increase timeouts * fix bug in set node * add transition on hover out * fix tooltip onboarding bug * only update expression if changes * add open delay * fix header highlight issue * update text * dont show tooltip always * update docs url * update ee border * add sticky behav * hide error highlight if dropping * switch out grip icon * increase timeout * add delay * show hint on execprev * add telemetry event * add telemetry event * add telemetry event * fire event on hint showing * fix telemetry event * add path * fix drag hint issue * decrease bottom margin * update mapping keys * remove file * hide overflow * sort params * add space * prevent scrolling * remove dropshadow * force cursor * address some comments * add thead tbody * add size opt --- .../N8nActionToggle/ActionToggle.stories.js | 6 +- .../N8nActionToggle/ActionToggle.vue | 40 +- .../components/N8nInputLabel/InputLabel.vue | 159 +++-- .../N8nRadioButtons/RadioButton.vue | 42 +- .../N8nRadioButtons/RadioButtons.stories.js | 4 + .../N8nRadioButtons/RadioButtons.vue | 17 +- .../src/components/N8nUsersList/UsersList.vue | 1 + .../src/styleguide/fonts.stories.mdx | 2 +- packages/design-system/theme/src/_tokens.scss | 17 + packages/design-system/theme/src/reset.scss | 1 - packages/editor-ui/package.json | 1 + packages/editor-ui/src/Interface.ts | 9 + .../editor-ui/src/components/Draggable.vue | 84 ++- .../src/components/DraggableTarget.vue | 80 +++ .../src/components/ExpressionEdit.vue | 13 +- .../src/components/ExpressionInput.vue | 2 +- .../components/FixedCollectionParameter.vue | 99 ++-- .../editor-ui/src/components/InputPanel.vue | 55 +- .../src/components/MultipleParameter.vue | 45 +- .../src/components/PanelDragButton.vue | 2 +- .../src/components/ParameterInput.vue | 546 ++++++++++-------- .../src/components/ParameterInputExpanded.vue | 75 ++- .../src/components/ParameterInputFull.vue | 136 ++++- .../src/components/ParameterInputList.vue | 36 +- .../src/components/ParameterOptions.vue | 164 ++++-- packages/editor-ui/src/components/RunData.vue | 68 +-- .../editor-ui/src/components/RunDataTable.vue | 287 +++++++++ .../editor-ui/src/components/ShortenName.vue | 13 +- packages/editor-ui/src/components/helpers.ts | 17 +- packages/editor-ui/src/constants.ts | 4 + packages/editor-ui/src/modules/ui.ts | 51 +- .../src/plugins/i18n/locales/en.json | 11 +- packages/editor-ui/src/plugins/icons.ts | 2 + 33 files changed, 1490 insertions(+), 599 deletions(-) create mode 100644 packages/editor-ui/src/components/DraggableTarget.vue create mode 100644 packages/editor-ui/src/components/RunDataTable.vue diff --git a/packages/design-system/src/components/N8nActionToggle/ActionToggle.stories.js b/packages/design-system/src/components/N8nActionToggle/ActionToggle.stories.js index 62ea3289f8a..f51148a3b12 100644 --- a/packages/design-system/src/components/N8nActionToggle/ActionToggle.stories.js +++ b/packages/design-system/src/components/N8nActionToggle/ActionToggle.stories.js @@ -7,7 +7,11 @@ export default { argTypes: { placement: { type: 'select', - options: ['top', 'bottom'], + options: ['top', 'top-start', 'top-end', 'bottom', 'bottom-end'], + }, + size: { + type: 'select', + options: ['mini', 'small', 'medium'], }, }, parameters: { diff --git a/packages/design-system/src/components/N8nActionToggle/ActionToggle.vue b/packages/design-system/src/components/N8nActionToggle/ActionToggle.vue index c73f3243094..d2fbc0621a6 100644 --- a/packages/design-system/src/components/N8nActionToggle/ActionToggle.vue +++ b/packages/design-system/src/components/N8nActionToggle/ActionToggle.vue @@ -1,9 +1,10 @@ @@ -120,6 +125,7 @@ import { DUPLICATE_MODAL_KEY, EXECUTIONS_MODAL_KEY, INVITE_USER_MODAL_KEY, + ONBOARDING_CALL_SIGNUP_MODAL_KEY, PERSONALIZATION_MODAL_KEY, TAGS_MANAGER_MODAL_KEY, VALUE_SURVEY_MODAL_KEY, @@ -140,6 +146,7 @@ import InviteUsersModal from "./InviteUsersModal.vue"; import CredentialsSelectModal from "./CredentialsSelectModal.vue"; import DuplicateWorkflowDialog from "./DuplicateWorkflowDialog.vue"; import ModalRoot from "./ModalRoot.vue"; +import OnboardingCallSignupModal from './OnboardingCallSignupModal.vue'; import PersonalizationModal from "./PersonalizationModal.vue"; import TagsManager from "./TagsManager/TagsManager.vue"; import UpdatesPanel from "./UpdatesPanel.vue"; @@ -167,6 +174,7 @@ export default Vue.extend({ InviteUsersModal, ExecutionsList, ModalRoot, + OnboardingCallSignupModal, PersonalizationModal, TagsManager, UpdatesPanel, @@ -185,6 +193,7 @@ export default Vue.extend({ CHANGE_PASSWORD_MODAL_KEY, DELETE_USER_MODAL_KEY, DUPLICATE_MODAL_KEY, + ONBOARDING_CALL_SIGNUP_MODAL_KEY, PERSONALIZATION_MODAL_KEY, INVITE_USER_MODAL_KEY, TAGS_MANAGER_MODAL_KEY, diff --git a/packages/editor-ui/src/components/OnboardingCallSignupModal.vue b/packages/editor-ui/src/components/OnboardingCallSignupModal.vue new file mode 100644 index 00000000000..aa57f26dff0 --- /dev/null +++ b/packages/editor-ui/src/components/OnboardingCallSignupModal.vue @@ -0,0 +1,128 @@ + + + + + diff --git a/packages/editor-ui/src/components/PersonalizationModal.vue b/packages/editor-ui/src/components/PersonalizationModal.vue index 0959b741d22..eed74e84f0c 100644 --- a/packages/editor-ui/src/components/PersonalizationModal.vue +++ b/packages/editor-ui/src/components/PersonalizationModal.vue @@ -108,6 +108,9 @@ import { OTHER_FOCUS, COMPANY_INDUSTRY_EXTENDED_KEY, OTHER_COMPANY_INDUSTRY_EXTENDED_KEY, + ONBOARDING_PROMPT_TIMEBOX, + FIRST_ONBOARDING_PROMPT_TIMEOUT, + ONBOARDING_CALL_SIGNUP_MODAL_KEY, } from '../constants'; import { workflowHelpers } from '@/components/mixins/workflowHelpers'; import { showMessage } from '@/components/mixins/showMessage'; @@ -115,6 +118,7 @@ import Modal from './Modal.vue'; import { IFormInput, IFormInputs, IPersonalizationSurveyAnswersV2 } from '@/Interface'; import Vue from 'vue'; import { mapGetters } from 'vuex'; +import { getAccountAge } from '@/modules/userHelpers'; export default mixins(showMessage, workflowHelpers).extend({ components: { Modal }, @@ -135,6 +139,12 @@ export default mixins(showMessage, workflowHelpers).extend({ ...mapGetters({ baseUrl: 'getBaseUrl', }), + ...mapGetters('users', [ + 'currentUser', + ]), + ...mapGetters('settings', [ + 'isOnboardingCallPromptFeatureEnabled', + ]), survey() { const survey: IFormInputs = [ { @@ -500,6 +510,7 @@ export default mixins(showMessage, workflowHelpers).extend({ this.closeDialog(); } + await this.fetchOnboardingPrompt(); this.submitted = true; } catch (e) { this.$showError(e, 'Error while submitting results'); @@ -507,6 +518,33 @@ export default mixins(showMessage, workflowHelpers).extend({ this.$data.isSaving = false; }, + async fetchOnboardingPrompt() { + if (this.isOnboardingCallPromptFeatureEnabled && getAccountAge(this.currentUser) <= ONBOARDING_PROMPT_TIMEBOX) { + const onboardingResponse = await this.$store.dispatch('ui/getNextOnboardingPrompt'); + const promptTimeout = onboardingResponse.toast_sequence_number === 1 ? FIRST_ONBOARDING_PROMPT_TIMEOUT : 1000; + + if (onboardingResponse.title && onboardingResponse.description) { + setTimeout(async () => { + this.$showToast({ + type: 'info', + title: onboardingResponse.title, + message: onboardingResponse.description, + duration: 0, + customClass: 'clickable', + closeOnClick: true, + onClick: () => { + this.$telemetry.track('user clicked onboarding toast', { + seq_num: onboardingResponse.toast_sequence_number, + title: onboardingResponse.title, + description: onboardingResponse.description, + }); + this.$store.commit('ui/openModal', ONBOARDING_CALL_SIGNUP_MODAL_KEY, {root: true}); + }, + }); + }, promptTimeout); + } + } + }, }, }); diff --git a/packages/editor-ui/src/components/SettingsSidebar.vue b/packages/editor-ui/src/components/SettingsSidebar.vue index 13392910041..c90984969d8 100644 --- a/packages/editor-ui/src/components/SettingsSidebar.vue +++ b/packages/editor-ui/src/components/SettingsSidebar.vue @@ -25,6 +25,17 @@ {{ $locale.baseText('settings.n8napi') }} + + + + + {{ $locale.baseText(fakeDoor.featureName) }} + @@ -45,6 +56,7 @@ import mixins from 'vue-typed-mixins'; import { mapGetters } from 'vuex'; import { ABOUT_MODAL_KEY, VIEWS } from '@/constants'; import { userHelpers } from './mixins/userHelpers'; +import { IFakeDoor } from '@/Interface'; export default mixins( userHelpers, @@ -52,6 +64,9 @@ export default mixins( name: 'SettingsSidebar', computed: { ...mapGetters('settings', ['versionCli']), + settingsFakeDoorFeatures(): IFakeDoor[] { + return this.$store.getters['ui/getFakeDoorByLocation']('settings'); + }, }, methods: { canAccessPersonalSettings(): boolean { diff --git a/packages/editor-ui/src/constants.ts b/packages/editor-ui/src/constants.ts index a6d81a7ba08..61af2391308 100644 --- a/packages/editor-ui/src/constants.ts +++ b/packages/editor-ui/src/constants.ts @@ -40,6 +40,7 @@ export const CONTACT_PROMPT_MODAL_KEY = 'contactPrompt'; export const VALUE_SURVEY_MODAL_KEY = 'valueSurvey'; export const EXECUTIONS_MODAL_KEY = 'executions'; export const WORKFLOW_ACTIVE_MODAL_KEY = 'activation'; +export const ONBOARDING_CALL_SIGNUP_MODAL_KEY = 'onboardingCallSignup'; export const COMMUNITY_PACKAGE_INSTALL_MODAL_KEY = 'communityPackageInstall'; export const COMMUNITY_PACKAGE_CONFIRM_MODAL_KEY = 'communityPackageManageConfirm'; @@ -55,7 +56,6 @@ export const BREAKPOINT_MD = 992; export const BREAKPOINT_LG = 1200; export const BREAKPOINT_XL = 1920; - export const N8N_IO_BASE_URL = `https://api.n8n.io/api/`; export const DATA_PINNING_DOCS_URL = 'https://docs.n8n.io/data/data-pinning/'; export const NPM_COMMUNITY_NODE_SEARCH_API_URL = `https://api.npms.io/v2/`; @@ -275,9 +275,19 @@ export enum VIEWS { PERSONAL_SETTINGS = "PersonalSettings", API_SETTINGS = "APISettings", NOT_FOUND = "NotFoundView", + FAKE_DOOR = "ComingSoon", COMMUNITY_NODES = "CommunityNodes", } +export enum FAKE_DOOR_FEATURES { + ENVIRONMENTS = 'environments', + LOGGING = 'logging', + SHARING = 'sharing', +} + +export const ONBOARDING_PROMPT_TIMEBOX = 14; +export const FIRST_ONBOARDING_PROMPT_TIMEOUT = 300000; + export const TEST_PIN_DATA = [ { name: "First item", diff --git a/packages/editor-ui/src/modules/settings.ts b/packages/editor-ui/src/modules/settings.ts index 094e49e3602..1556dc9da30 100644 --- a/packages/editor-ui/src/modules/settings.ts +++ b/packages/editor-ui/src/modules/settings.ts @@ -30,6 +30,7 @@ const module: Module = { latestVersion: 0, path: '/', }, + onboardingCallPromptEnabled: false, }, getters: { versionCli(state: ISettingsState) { @@ -83,6 +84,9 @@ const module: Module = { templatesHost: (state): string => { return state.settings.templates.host; }, + isOnboardingCallPromptFeatureEnabled: (state): boolean => { + return state.onboardingCallPromptEnabled; + }, isCommunityNodesFeatureEnabled: (state): boolean => { return state.settings.communityNodesEnabled; }, @@ -99,6 +103,7 @@ const module: Module = { state.api.enabled = settings.publicApi.enabled; state.api.latestVersion = settings.publicApi.latestVersion; state.api.path = settings.publicApi.path; + state.onboardingCallPromptEnabled = settings.onboardingCallPromptEnabled; }, stopShowingSetupPage(state: ISettingsState) { Vue.set(state.userManagement, 'showSetupOnFirstLoad', false); diff --git a/packages/editor-ui/src/modules/ui.ts b/packages/editor-ui/src/modules/ui.ts index 877b1eee81e..f8ee3103661 100644 --- a/packages/editor-ui/src/modules/ui.ts +++ b/packages/editor-ui/src/modules/ui.ts @@ -1,3 +1,4 @@ +import { applyForOnboardingCall, fetchNextOnboardingPrompt, submitEmailOnSignup } from '@/api/workflow-webhooks'; import { ABOUT_MODAL_KEY, COMMUNITY_PACKAGE_CONFIRM_MODAL_KEY, @@ -19,11 +20,15 @@ import { WORKFLOW_OPEN_MODAL_KEY, WORKFLOW_SETTINGS_MODAL_KEY, VIEWS, + ONBOARDING_CALL_SIGNUP_MODAL_KEY, + FAKE_DOOR_FEATURES, COMMUNITY_PACKAGE_MANAGE_ACTIONS, } from '@/constants'; import Vue from 'vue'; import { ActionContext, Module } from 'vuex'; import { + IFakeDoor, + IFakeDoorLocation, IRootState, IRunDataDisplayMode, IUiState, @@ -61,6 +66,9 @@ const module: Module = { [DUPLICATE_MODAL_KEY]: { open: false, }, + [ONBOARDING_CALL_SIGNUP_MODAL_KEY]: { + open: false, + }, [PERSONALIZATION_MODAL_KEY]: { open: false, }, @@ -117,6 +125,36 @@ const module: Module = { mappingTelemetry: {}, }, mainPanelPosition: 0.5, + fakeDoorFeatures: [ + { + id: FAKE_DOOR_FEATURES.ENVIRONMENTS, + featureName: 'fakeDoor.settings.environments.name', + icon: 'server', + infoText: 'fakeDoor.settings.environments.infoText', + actionBoxTitle: 'fakeDoor.settings.environments.actionBox.title', + actionBoxDescription: 'fakeDoor.settings.environments.actionBox.description', + linkURL: 'https://n8n-community.typeform.com/to/l7QOrERN#f=environments', + uiLocations: ['settings'], + }, + { + id: FAKE_DOOR_FEATURES.LOGGING, + featureName: 'fakeDoor.settings.logging.name', + icon: 'sign-in-alt', + infoText: 'fakeDoor.settings.logging.infoText', + actionBoxTitle: 'fakeDoor.settings.logging.actionBox.title', + actionBoxDescription: 'fakeDoor.settings.logging.actionBox.description', + linkURL: 'https://n8n-community.typeform.com/to/l7QOrERN#f=logging', + uiLocations: ['settings'], + }, + { + id: FAKE_DOOR_FEATURES.SHARING, + featureName: 'fakeDoor.credentialEdit.sharing.name', + actionBoxTitle: 'fakeDoor.credentialEdit.sharing.actionBox.title', + actionBoxDescription: 'fakeDoor.credentialEdit.sharing.actionBox.description', + linkURL: 'https://n8n-community.typeform.com/to/l7QOrERN#f=sharing', + uiLocations: ['credentialsModal'], + }, + ], draggable: { isDragging: false, type: '', @@ -153,6 +191,13 @@ const module: Module = { outputPanelDispalyMode: (state: IUiState) => state.ndv.output.displayMode, outputPanelEditMode: (state: IUiState): IUiState['ndv']['output']['editMode'] => state.ndv.output.editMode, mainPanelPosition: (state: IUiState) => state.mainPanelPosition, + getFakeDoorFeatures: (state: IUiState) => state.fakeDoorFeatures, + getFakeDoorByLocation: (state: IUiState) => (location: IFakeDoorLocation) => { + return state.fakeDoorFeatures.filter(fakeDoor => fakeDoor.uiLocations.includes(location)); + }, + getFakeDoorById: (state: IUiState) => (id: string) => { + return state.fakeDoorFeatures.find(fakeDoor => fakeDoor.id.toString() === id); + }, focusedMappableInput: (state: IUiState) => state.ndv.focusedMappableInput, isDraggableDragging: (state: IUiState) => state.draggable.isDragging, draggableType: (state: IUiState) => state.draggable.type, @@ -264,6 +309,21 @@ const module: Module = { context.commit('setMode', { name: CREDENTIAL_EDIT_MODAL_KEY, mode: 'new' }); context.commit('openModal', CREDENTIAL_EDIT_MODAL_KEY); }, + getNextOnboardingPrompt: async (context: ActionContext) => { + const instanceId = context.rootGetters.instanceId; + const currentUser = context.rootGetters['users/currentUser']; + return await fetchNextOnboardingPrompt(instanceId, currentUser); + }, + applyForOnboardingCall: async (context: ActionContext, { email }) => { + const instanceId = context.rootGetters.instanceId; + const currentUser = context.rootGetters['users/currentUser']; + return await applyForOnboardingCall(instanceId, currentUser, email); + }, + submitContactEmail: async (context: ActionContext, { email, agree }) => { + const instanceId = context.rootGetters.instanceId; + const currentUser = context.rootGetters['users/currentUser']; + return await submitEmailOnSignup(instanceId, currentUser, email, agree); + }, async openCommunityPackageUninstallConfirmModal(context: ActionContext, packageName: string) { context.commit('setActiveId', { name: COMMUNITY_PACKAGE_CONFIRM_MODAL_KEY, id: packageName}); context.commit('setMode', { name: COMMUNITY_PACKAGE_CONFIRM_MODAL_KEY, mode: COMMUNITY_PACKAGE_MANAGE_ACTIONS.UNINSTALL }); diff --git a/packages/editor-ui/src/modules/userHelpers.ts b/packages/editor-ui/src/modules/userHelpers.ts index 05a6d23bf70..44ba0b528eb 100644 --- a/packages/editor-ui/src/modules/userHelpers.ts +++ b/packages/editor-ui/src/modules/userHelpers.ts @@ -108,6 +108,16 @@ export function getPersonalizedNodeTypes(answers: IPersonalizationSurveyAnswersV return getPersonalizationV1(answers as IPersonalizationSurveyAnswersV1); } +export function getAccountAge(currentUser: IUser): number { + if(currentUser.createdAt) { + const accountCreatedAt = new Date(currentUser.createdAt); + const today = new Date(); + + return Math.ceil((today.getTime() - accountCreatedAt.getTime()) / (1000* 3600 * 24)); + } + return -1; +} + function getPersonalizationV2(answers: IPersonalizationSurveyAnswersV2) { let nodeTypes: string[] = []; diff --git a/packages/editor-ui/src/plugins/i18n/locales/en.json b/packages/editor-ui/src/plugins/i18n/locales/en.json index 6e94459cfad..1cbdca6fd98 100644 --- a/packages/editor-ui/src/plugins/i18n/locales/en.json +++ b/packages/editor-ui/src/plugins/i18n/locales/en.json @@ -18,6 +18,8 @@ "generic.clickToCopy": "Click to copy", "generic.copiedToClipboard": "Copied to clipboard", "generic.beta": "beta", + "generic.yes": "Yes", + "generic.no": "No", "about.aboutN8n": "About n8n", "about.close": "Close", "about.license": "License", @@ -55,6 +57,7 @@ "auth.role": "Role", "auth.roles.member": "Member", "auth.roles.owner": "Owner", + "auth.agreement.label": "I’d be OK sharing my opinion on n8n (no marketing emails though)", "auth.setup.confirmOwnerSetup": "Set up owner account?", "auth.setup.confirmOwnerSetupMessage": "To give others access to your {entities}, you’ll need to share these account details with them. Or you can continue as before with no account, by going back and skipping this setup. More info", "auth.setup.createAccount": "Create account", @@ -248,6 +251,18 @@ "expressionEdit.expression": "Expression", "expressionEdit.result": "Result", "expressionEdit.variableSelector": "Variable Selector", + "fakeDoor.credentialEdit.sharing.name": "Sharing", + "fakeDoor.credentialEdit.sharing.actionBox.title": "We're working on sharing (as a paid feature)", + "fakeDoor.credentialEdit.sharing.actionBox.description": "If you'd like to be the first to hear when it's ready, join the list", + "fakeDoor.settings.environments.name": "Environments", + "fakeDoor.settings.environments.infoText": "Environments allow you to use different settings and credentials in a workflow when you're building it vs when it's running in production", + "fakeDoor.settings.environments.actionBox.title": "We're working on this (as a paid feature)", + "fakeDoor.settings.environments.actionBox.description": "If you'd like to be the first to hear when it's ready, join the list.", + "fakeDoor.settings.logging.name": "Logging", + "fakeDoor.settings.logging.infoText": "You can already write logs to a file or the console using environment variables. More info", + "fakeDoor.settings.logging.actionBox.title": "We're working on advanced logging (as a paid feature)", + "fakeDoor.settings.logging.actionBox.description": "This also includes audit logging. If you'd like to be the first to hear when it's ready, join the list.", + "fakeDoor.actionBox.button.label": "Join the list", "fixedCollectionParameter.choose": "Choose...", "fixedCollectionParameter.currentlyNoItemsExist": "Currently no items exist", "fixedCollectionParameter.deleteItem": "Delete item", @@ -556,6 +571,17 @@ "nodeWebhooks.showMessage.title": "URL copied", "nodeWebhooks.testUrl": "Test URL", "nodeWebhooks.webhookUrls": "Webhook URLs", + "onboardingCallSignupModal.title": "Your onboarding session", + "onboardingCallSignupModal.description": "Pop in your email and we'll send you some scheduling options", + "onboardingCallSignupModal.emailInput.placeholder": "Your work email", + "onboardingCallSignupModal.signupButton.label": "Submit", + "onboardingCallSignupModal.cancelButton.label": "Cancel", + "onboardingCallSignupModal.infoText.emailError": "This doesn't seem to be a valid email address", + "onboardingCallSignupSucess.title": "Successfully signed up for an onboarding session", + "onboardingCallSignupSucess.message": "You should receive a message from us shortly", + "onboardingCallSignupFailed.title": "Something went wrong", + "onboardingCallSignupFailed.message": "Your request could not be sent", + "onboardingCallSignupModal.confirmExit.title": "Are you sure?", "onboardingWorkflow.stickyContent": "## 👇 Get started faster \nLightning tour of the key concepts \n\n[![n8n quickstart video](/static/quickstart_thumbnail.png#full-width)](https://www.youtube.com/watch?v=RpjQTGKm-ok)", "openWorkflow.workflowImportError": "Could not import workflow", "openWorkflow.workflowNotFoundError": "Could not find workflow", diff --git a/packages/editor-ui/src/router.ts b/packages/editor-ui/src/router.ts index cc1d05f8a1c..086116d2b99 100644 --- a/packages/editor-ui/src/router.ts +++ b/packages/editor-ui/src/router.ts @@ -10,6 +10,7 @@ import SettingsPersonalView from './views/SettingsPersonalView.vue'; import SettingsUsersView from './views/SettingsUsersView.vue'; import SettingsCommunityNodesView from './views/SettingsCommunityNodesView.vue'; import SettingsApiView from './views/SettingsApiView.vue'; +import SettingsFakeDoorView from './views/SettingsFakeDoorView.vue'; import SetupView from './views/SetupView.vue'; import SigninView from './views/SigninView.vue'; import SignupView from './views/SignupView.vue'; @@ -328,6 +329,11 @@ const router = new Router({ meta: { telemetry: { pageCategory: 'settings', + getProperties(route: Route, store: Store) { + return { + feature: 'users', + }; + }, }, permissions: { allow: { @@ -350,6 +356,11 @@ const router = new Router({ meta: { telemetry: { pageCategory: 'settings', + getProperties(route: Route, store: Store) { + return { + feature: 'personal', + }; + }, }, permissions: { allow: { @@ -370,6 +381,11 @@ const router = new Router({ meta: { telemetry: { pageCategory: 'settings', + getProperties(route: Route, store: Store) { + return { + feature: 'api', + }; + }, }, permissions: { allow: { @@ -405,6 +421,27 @@ const router = new Router({ }, }, }, + { + path: '/settings/coming-soon/:featureId', + name: VIEWS.FAKE_DOOR, + component: SettingsFakeDoorView, + props: true, + meta: { + telemetry: { + pageCategory: 'settings', + getProperties(route: Route, store: Store) { + return { + feature: route.params['featureId'], + }; + }, + }, + permissions: { + allow: { + loginStatus: [LOGIN_STATUS.LoggedIn], + }, + }, + }, + }, { path: '*', name: VIEWS.NOT_FOUND, @@ -422,6 +459,7 @@ const router = new Router({ }, permissions: { allow: { + // TODO: Once custom permissions are merged, this needs to be updated with index validation loginStatus: [LOGIN_STATUS.LoggedIn, LOGIN_STATUS.LoggedOut], }, }, diff --git a/packages/editor-ui/src/views/AuthView.vue b/packages/editor-ui/src/views/AuthView.vue index 8b5558dbf98..8fc53ce9887 100644 --- a/packages/editor-ui/src/views/AuthView.vue +++ b/packages/editor-ui/src/views/AuthView.vue @@ -84,3 +84,10 @@ body { } + diff --git a/packages/editor-ui/src/views/NodeView.vue b/packages/editor-ui/src/views/NodeView.vue index e2c1e9a5a0d..6374ab0abb2 100644 --- a/packages/editor-ui/src/views/NodeView.vue +++ b/packages/editor-ui/src/views/NodeView.vue @@ -154,7 +154,25 @@ import { } from 'jsplumb'; import { MessageBoxInputData } from 'element-ui/types/message-box'; import { jsPlumb, OnConnectionBindInfo } from 'jsplumb'; -import { DEFAULT_STICKY_HEIGHT, DEFAULT_STICKY_WIDTH, MODAL_CANCEL, MODAL_CLOSE, MODAL_CONFIRMED, NODE_NAME_PREFIX, NODE_OUTPUT_DEFAULT_KEY, PLACEHOLDER_EMPTY_WORKFLOW_ID, QUICKSTART_NOTE_NAME, START_NODE_TYPE, STICKY_NODE_TYPE, VIEWS, WEBHOOK_NODE_TYPE, WORKFLOW_OPEN_MODAL_KEY } from '@/constants'; +import { + DEFAULT_STICKY_HEIGHT, + DEFAULT_STICKY_WIDTH, + FIRST_ONBOARDING_PROMPT_TIMEOUT, + MODAL_CANCEL, + MODAL_CLOSE, + MODAL_CONFIRMED, + NODE_NAME_PREFIX, + NODE_OUTPUT_DEFAULT_KEY, + ONBOARDING_CALL_SIGNUP_MODAL_KEY, + ONBOARDING_PROMPT_TIMEBOX, + PLACEHOLDER_EMPTY_WORKFLOW_ID, + QUICKSTART_NOTE_NAME, + START_NODE_TYPE, + STICKY_NODE_TYPE, + VIEWS, + WEBHOOK_NODE_TYPE, + WORKFLOW_OPEN_MODAL_KEY, +} from '@/constants'; import { copyPaste } from '@/components/mixins/copyPaste'; import { externalHooks } from '@/components/mixins/externalHooks'; import { genericHelpers } from '@/components/mixins/genericHelpers'; @@ -215,11 +233,12 @@ import { mapGetters } from 'vuex'; import { addNodeTranslation, - addHeaders, } from '@/plugins/i18n'; import '../plugins/N8nCustomConnectorType'; import '../plugins/PlusEndpointType'; +import { getAccountAge } from '@/modules/userHelpers'; +import { IUser } from 'n8n-design-system'; import {dataPinningEventBus} from "@/event-bus/data-pinning-event-bus"; interface AddNodeOptions { @@ -312,9 +331,15 @@ export default mixins( } }, computed: { + ...mapGetters('users', [ + 'currentUser', + ]), ...mapGetters('ui', [ 'sidebarMenuCollapsed', ]), + ...mapGetters('settings', [ + 'isOnboardingCallPromptFeatureEnabled', + ]), defaultLocale (): string { return this.$store.getters.defaultLocale; }, @@ -3060,6 +3085,35 @@ export default mixins( this.$externalHooks().run('nodeView.mount'); + if ( + this.currentUser.personalizationAnswers !== null && + this.isOnboardingCallPromptFeatureEnabled && + getAccountAge(this.currentUser) <= ONBOARDING_PROMPT_TIMEBOX + ) { + const onboardingResponse = await this.$store.dispatch('ui/getNextOnboardingPrompt'); + const promptTimeout = onboardingResponse.toast_sequence_number === 1 ? FIRST_ONBOARDING_PROMPT_TIMEOUT : 1000; + + if (onboardingResponse.title && onboardingResponse.description) { + setTimeout(async () => { + this.$showToast({ + type: 'info', + title: onboardingResponse.title, + message: onboardingResponse.description, + duration: 0, + customClass: 'clickable', + closeOnClick: true, + onClick: () => { + this.$telemetry.track('user clicked onboarding toast', { + seq_num: onboardingResponse.toast_sequence_number, + title: onboardingResponse.title, + description: onboardingResponse.description, + }); + this.$store.commit('ui/openModal', ONBOARDING_CALL_SIGNUP_MODAL_KEY, {root: true}); + }, + }); + }, promptTimeout); + } + } dataPinningEventBus.$on('pin-data', this.addPinDataConnections); dataPinningEventBus.$on('unpin-data', this.removePinDataConnections); }, diff --git a/packages/editor-ui/src/views/SettingsFakeDoorView.vue b/packages/editor-ui/src/views/SettingsFakeDoorView.vue new file mode 100644 index 00000000000..7284c081417 --- /dev/null +++ b/packages/editor-ui/src/views/SettingsFakeDoorView.vue @@ -0,0 +1,39 @@ + + + + + diff --git a/packages/editor-ui/src/views/SetupView.vue b/packages/editor-ui/src/views/SetupView.vue index d67966bde1d..ab508f52dbc 100644 --- a/packages/editor-ui/src/views/SetupView.vue +++ b/packages/editor-ui/src/views/SetupView.vue @@ -79,6 +79,13 @@ export default mixins( capitalize: true, }, }, + { + name: 'agree', + properties: { + label: this.$locale.baseText('auth.agreement.label'), + type: 'checkbox', + }, + }, ], }; @@ -130,7 +137,7 @@ export default mixins( this.$locale.baseText('auth.setup.goBack'), ); }, - async onSubmit(values: {[key: string]: string}) { + async onSubmit(values: {[key: string]: string | boolean}) { try { const confirmSetup = await this.confirmSetupOrGoBack(); if (!confirmSetup) { @@ -140,6 +147,13 @@ export default mixins( const forceRedirectedHere = this.$store.getters['settings/showSetupPage']; this.loading = true; await this.$store.dispatch('users/createOwner', values); + + if (values.agree === true) { + try { + await this.$store.dispatch('ui/submitContactEmail', { email: values.email, agree: values.agree }); + } catch { } + } + if (forceRedirectedHere) { await this.$router.push({ name: VIEWS.HOMEPAGE }); } diff --git a/packages/editor-ui/src/views/SignupView.vue b/packages/editor-ui/src/views/SignupView.vue index 80d95b79f35..9553a2b5661 100644 --- a/packages/editor-ui/src/views/SignupView.vue +++ b/packages/editor-ui/src/views/SignupView.vue @@ -59,6 +59,13 @@ export default mixins( capitalize: true, }, }, + { + name: 'agree', + properties: { + label: this.$locale.baseText('auth.agreement.label'), + type: 'checkbox', + }, + }, ], }; return { @@ -95,13 +102,19 @@ export default mixins( }, }, methods: { - async onSubmit(values: {[key: string]: string}) { + async onSubmit(values: {[key: string]: string | boolean}) { try { this.loading = true; const inviterId = this.$route.query.inviterId; const inviteeId = this.$route.query.inviteeId; await this.$store.dispatch('users/signup', {...values, inviterId, inviteeId}); + if (values.agree === true) { + try { + await this.$store.dispatch('ui/submitContactEmail', { email: values.email, agree: values.agree }); + } catch { } + } + await this.$router.push({ name: VIEWS.HOMEPAGE }); } catch (error) { this.$showError(error, this.$locale.baseText('auth.signup.setupYourAccountError')); From 3496a39788b654b46485955ba5cce5e5865babc7 Mon Sep 17 00:00:00 2001 From: Michael Kret <88898367+michael-radency@users.noreply.github.com> Date: Wed, 27 Jul 2022 18:00:39 +0300 Subject: [PATCH 057/609] feat(Kafka Trigger Node): Add additional options (#3600) * :hammer: additional options to kafka trigger * :zap: option for maxInFlightRequests * :zap: Small change Co-authored-by: ricardo --- .../nodes/Kafka/KafkaTrigger.node.ts | 54 ++++++++++++++++--- 1 file changed, 46 insertions(+), 8 deletions(-) diff --git a/packages/nodes-base/nodes/Kafka/KafkaTrigger.node.ts b/packages/nodes-base/nodes/Kafka/KafkaTrigger.node.ts index 22c26a163a2..a1bea2f47ef 100644 --- a/packages/nodes-base/nodes/Kafka/KafkaTrigger.node.ts +++ b/packages/nodes-base/nodes/Kafka/KafkaTrigger.node.ts @@ -94,6 +94,36 @@ export class KafkaTrigger implements INodeType { default: false, description: 'Whether to allow sending message to a previously non exisiting topic', }, + { + displayName: 'Auto Commit Threshold', + name: 'autoCommitThreshold', + type: 'number', + default: 0, + description: 'The consumer will commit offsets after resolving a given number of messages', + }, + { + displayName: 'Auto Commit Interval', + name: 'autoCommitInterval', + type: 'number', + default: 0, + description: 'The consumer will commit offsets after a given period, for example, five seconds', + hint: 'Value in milliseconds', + }, + { + displayName: 'Heartbeat Interval', + name: 'heartbeatInterval', + type: 'number', + default: 3000, + description: 'Heartbeats are used to ensure that the consumer\'s session stays active', + hint: 'The value must be set lower than Session Timeout', + }, + { + displayName: 'Max Number of Requests', + name: 'maxInFlightRequests', + type: 'number', + default: 0, + description: 'Max number of requests that may be in progress at any time. If falsey then no limit.', + }, { displayName: 'Read Messages From Beginning', name: 'fromBeginning', @@ -122,13 +152,6 @@ export class KafkaTrigger implements INodeType { default: false, description: 'Whether to return only the message property', }, - { - displayName: 'Session Timeout', - name: 'sessionTimeout', - type: 'number', - default: 30000, - description: 'The time to await a response in ms', - }, { displayName: 'Return Headers', name: 'returnHeaders', @@ -136,6 +159,14 @@ export class KafkaTrigger implements INodeType { default: false, description: 'Whether to return the headers received from Kafka', }, + { + displayName: 'Session Timeout', + name: 'sessionTimeout', + type: 'number', + default: 30000, + description: 'The time to await a response in ms', + hint: 'Value in milliseconds', + }, ], }, ], @@ -175,7 +206,12 @@ export class KafkaTrigger implements INodeType { const kafka = new apacheKafka(config); - const consumer = kafka.consumer({ groupId }); + const consumer = kafka.consumer({ + groupId, + maxInFlightRequests: this.getNodeParameter('options.maxInFlightRequests', 0) as number, + sessionTimeout: this.getNodeParameter('options.sessionTimeout', 30000) as number, + heartbeatInterval: this.getNodeParameter('options.heartbeatInterval', 3000) as number, + }); await consumer.connect(); @@ -191,6 +227,8 @@ export class KafkaTrigger implements INodeType { const startConsumer = async () => { await consumer.run({ + autoCommitInterval: options.autoCommitInterval as number || null, + autoCommitThreshold: options.autoCommitThreshold as number || null, eachMessage: async ({ topic, message }) => { let data: IDataObject = {}; From 30c0f21b3f37280403848592877cb8658367b85e Mon Sep 17 00:00:00 2001 From: Alex Grozav Date: Wed, 27 Jul 2022 18:02:46 +0300 Subject: [PATCH 058/609] fix(editor): Fix pin data in executions when pinData is null. (#3787) --- packages/editor-ui/src/store.ts | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/packages/editor-ui/src/store.ts b/packages/editor-ui/src/store.ts index db8da977509..eea0f5f192e 100644 --- a/packages/editor-ui/src/store.ts +++ b/packages/editor-ui/src/store.ts @@ -214,20 +214,23 @@ export const store = new Vuex.Store({ // Pin data pinData(state, payload: { node: INodeUi, data: IPinData[string] }) { - if (state.workflow.pinData) { - Vue.set(state.workflow.pinData, payload.node.name, payload.data); + if (!state.workflow.pinData) { + Vue.set(state.workflow, 'pinData', {}); } + Vue.set(state.workflow.pinData!, payload.node.name, payload.data); state.stateIsDirty = true; dataPinningEventBus.$emit('pin-data', { [payload.node.name]: payload.data }); }, unpinData(state, payload: { node: INodeUi }) { - if (state.workflow.pinData) { - Vue.set(state.workflow.pinData, payload.node.name, undefined); - delete state.workflow.pinData[payload.node.name]; + if (!state.workflow.pinData) { + Vue.set(state.workflow, 'pinData', {}); } + Vue.set(state.workflow.pinData!, payload.node.name, undefined); + delete state.workflow.pinData![payload.node.name]; + state.stateIsDirty = true; dataPinningEventBus.$emit('unpin-data', { [payload.node.name]: undefined }); @@ -478,7 +481,7 @@ export const store = new Vuex.Store({ } if (data.removePinData) { - state.workflow.pinData = {}; + Vue.set(state.workflow, 'pinData', {}); } state.workflow.nodes.splice(0, state.workflow.nodes.length); @@ -652,9 +655,9 @@ export const store = new Vuex.Store({ }, setWorkflowPinData(state, pinData: IPinData) { - Vue.set(state.workflow, 'pinData', pinData); + Vue.set(state.workflow, 'pinData', pinData || {}); - dataPinningEventBus.$emit('pin-data', pinData); + dataPinningEventBus.$emit('pin-data', pinData || {}); }, setWorkflowTagIds(state, tags: string[]) { @@ -909,7 +912,7 @@ export const store = new Vuex.Store({ return state.workflow.pinData; }, pinDataByNodeName: (state) => (nodeName: string) => { - return state.workflow.pinData && state.workflow.pinData[nodeName]; + return state.workflow.pinData ? state.workflow.pinData[nodeName] : undefined; }, pinDataSize: (state) => { return state.workflow.nodes From 2971ef9ec017428c2f39f22096bdd24125fd0143 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Wed, 27 Jul 2022 17:38:39 +0200 Subject: [PATCH 059/609] :arrow_up: Update package-lock.json file --- package-lock.json | 1748 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 1326 insertions(+), 422 deletions(-) diff --git a/package-lock.json b/package-lock.json index 19217c1f363..f9eef4ce72c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2962,21 +2962,21 @@ } }, "node_modules/@fortawesome/free-regular-svg-icons": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.1.1.tgz", - "integrity": "sha512-xXiW7hcpgwmWtndKPOzG+43fPH7ZjxOaoeyooptSztGmJxCAflHZxXNK0GcT0uEsR4jTGQAfGklDZE5NHoBhKg==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.1.2.tgz", + "integrity": "sha512-xR4hA+tAwsaTHGfb+25H1gVU/aJ0Rzu+xIUfnyrhaL13yNQ7TWiI2RvzniAaB+VGHDU2a+Pk96Ve+pkN3/+TTQ==", "hasInstallScript": true, "dependencies": { - "@fortawesome/fontawesome-common-types": "6.1.1" + "@fortawesome/fontawesome-common-types": "6.1.2" }, "engines": { "node": ">=6" } }, "node_modules/@fortawesome/free-regular-svg-icons/node_modules/@fortawesome/fontawesome-common-types": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.1.1.tgz", - "integrity": "sha512-wVn5WJPirFTnzN6tR95abCx+ocH+3IFLXAgyavnf9hUmN0CfWoDjPT/BAWsUVwSlYYVBeCLJxaqi7ZGe4uSjBA==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.1.2.tgz", + "integrity": "sha512-wBaAPGz1Awxg05e0PBRkDRuTsy4B3dpBm+zreTTyd9TH4uUM27cAL4xWyWR0rLJCrRwzVsQ4hF3FvM6rqydKPA==", "hasInstallScript": true, "engines": { "node": ">=6" @@ -14902,9 +14902,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.29", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.29.tgz", - "integrity": "sha512-uMd++6dMKS32EOuw1Uli3e3BPgdLIXmezcfHv7N4c1s3gkhikBplORPpMq3fuWkxncZN1reb16d5n8yhQ80x7Q==", + "version": "4.17.30", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.30.tgz", + "integrity": "sha512-gstzbTWro2/nFed1WXtf+TtrpwxH7Ggs4RLYTLbeVgIkUQOI3WG/JKjgeOU1zXDvezllupjrf8OPIdvTbIaVOQ==", "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -15398,9 +15398,9 @@ } }, "node_modules/@types/prettier": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.6.3.tgz", - "integrity": "sha512-ymZk3LEC/fsut+/Q5qejp6R9O1rMxz3XaRHDV6kX8MrGAhOSPqVARbDi+EZvInBpw+BnCX3TD240byVkOfQsHg==" + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.6.4.tgz", + "integrity": "sha512-fOwvpvQYStpb/zHMx0Cauwywu9yLDmzWiiQBC7gJyq5tYLUXFZvDG7VK1B7WBxxjBJNKFOZ0zLoOQn8vmATbhw==" }, "node_modules/@types/pretty-hrtime": { "version": "1.0.1", @@ -15782,13 +15782,13 @@ "integrity": "sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw==" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.30.7", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.7.tgz", - "integrity": "sha512-l4L6Do+tfeM2OK0GJsU7TUcM/1oN/N25xHm3Jb4z3OiDU4Lj8dIuxX9LpVMS9riSXQs42D1ieX7b85/r16H9Fw==", + "version": "5.31.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.31.0.tgz", + "integrity": "sha512-VKW4JPHzG5yhYQrQ1AzXgVgX8ZAJEvCz0QI6mLRX4tf7rnFfh5D8SKm0Pq6w5PyNfAWJk6sv313+nEt3ohWMBQ==", "dependencies": { - "@typescript-eslint/scope-manager": "5.30.7", - "@typescript-eslint/type-utils": "5.30.7", - "@typescript-eslint/utils": "5.30.7", + "@typescript-eslint/scope-manager": "5.31.0", + "@typescript-eslint/type-utils": "5.31.0", + "@typescript-eslint/utils": "5.31.0", "debug": "^4.3.4", "functional-red-black-tree": "^1.0.1", "ignore": "^5.2.0", @@ -15844,13 +15844,13 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/@typescript-eslint/parser": { - "version": "5.30.7", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.30.7.tgz", - "integrity": "sha512-Rg5xwznHWWSy7v2o0cdho6n+xLhK2gntImp0rJroVVFkcYFYQ8C8UJTSuTw/3CnExBmPjycjmUJkxVmjXsld6A==", + "version": "5.31.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.31.0.tgz", + "integrity": "sha512-UStjQiZ9OFTFReTrN+iGrC6O/ko9LVDhreEK5S3edmXgR396JGq7CoX2TWIptqt/ESzU2iRKXAHfSF2WJFcWHw==", "dependencies": { - "@typescript-eslint/scope-manager": "5.30.7", - "@typescript-eslint/types": "5.30.7", - "@typescript-eslint/typescript-estree": "5.30.7", + "@typescript-eslint/scope-manager": "5.31.0", + "@typescript-eslint/types": "5.31.0", + "@typescript-eslint/typescript-estree": "5.31.0", "debug": "^4.3.4" }, "engines": { @@ -15870,12 +15870,12 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.30.7", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.7.tgz", - "integrity": "sha512-7BM1bwvdF1UUvt+b9smhqdc/eniOnCKxQT/kj3oXtj3LqnTWCAM0qHRHfyzCzhEfWX0zrW7KqXXeE4DlchZBKw==", + "version": "5.31.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.31.0.tgz", + "integrity": "sha512-8jfEzBYDBG88rcXFxajdVavGxb5/XKXyvWgvD8Qix3EEJLCFIdVloJw+r9ww0wbyNLOTYyBsR+4ALNGdlalLLg==", "dependencies": { - "@typescript-eslint/types": "5.30.7", - "@typescript-eslint/visitor-keys": "5.30.7" + "@typescript-eslint/types": "5.31.0", + "@typescript-eslint/visitor-keys": "5.31.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -15886,11 +15886,11 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.30.7", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.30.7.tgz", - "integrity": "sha512-nD5qAE2aJX/YLyKMvOU5jvJyku4QN5XBVsoTynFrjQZaDgDV6i7QHFiYCx10wvn7hFvfuqIRNBtsgaLe0DbWhw==", + "version": "5.31.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.31.0.tgz", + "integrity": "sha512-7ZYqFbvEvYXFn9ax02GsPcEOmuWNg+14HIf4q+oUuLnMbpJ6eHAivCg7tZMVwzrIuzX3QCeAOqKoyMZCv5xe+w==", "dependencies": { - "@typescript-eslint/utils": "5.30.7", + "@typescript-eslint/utils": "5.31.0", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -15911,9 +15911,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.30.7", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.7.tgz", - "integrity": "sha512-ocVkETUs82+U+HowkovV6uxf1AnVRKCmDRNUBUUo46/5SQv1owC/EBFkiu4MOHeZqhKz2ktZ3kvJJ1uFqQ8QPg==", + "version": "5.31.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.31.0.tgz", + "integrity": "sha512-/f/rMaEseux+I4wmR6mfpM2wvtNZb1p9hAV77hWfuKc3pmaANp5dLAZSiE3/8oXTYTt3uV9KW5yZKJsMievp6g==", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -15923,12 +15923,12 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.30.7", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.7.tgz", - "integrity": "sha512-tNslqXI1ZdmXXrHER83TJ8OTYl4epUzJC0aj2i4DMDT4iU+UqLT3EJeGQvJ17BMbm31x5scSwo3hPM0nqQ1AEA==", + "version": "5.31.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.31.0.tgz", + "integrity": "sha512-3S625TMcARX71wBc2qubHaoUwMEn+l9TCsaIzYI/ET31Xm2c9YQ+zhGgpydjorwQO9pLfR/6peTzS/0G3J/hDw==", "dependencies": { - "@typescript-eslint/types": "5.30.7", - "@typescript-eslint/visitor-keys": "5.30.7", + "@typescript-eslint/types": "5.31.0", + "@typescript-eslint/visitor-keys": "5.31.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -15979,14 +15979,14 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/@typescript-eslint/utils": { - "version": "5.30.7", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.30.7.tgz", - "integrity": "sha512-Z3pHdbFw+ftZiGUnm1GZhkJgVqsDL5CYW2yj+TB2mfXDFOMqtbzQi2dNJIyPqPbx9mv2kUxS1gU+r2gKlKi1rQ==", + "version": "5.31.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.31.0.tgz", + "integrity": "sha512-kcVPdQS6VIpVTQ7QnGNKMFtdJdvnStkqS5LeALr4rcwx11G6OWb2HB17NMPnlRHvaZP38hL9iK8DdE9Fne7NYg==", "dependencies": { "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.30.7", - "@typescript-eslint/types": "5.30.7", - "@typescript-eslint/typescript-estree": "5.30.7", + "@typescript-eslint/scope-manager": "5.31.0", + "@typescript-eslint/types": "5.31.0", + "@typescript-eslint/typescript-estree": "5.31.0", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0" }, @@ -16002,11 +16002,11 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.30.7", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.7.tgz", - "integrity": "sha512-KrRXf8nnjvcpxDFOKej4xkD7657+PClJs5cJVSG7NNoCNnjEdc46juNAQt7AyuWctuCgs6mVRc1xGctEqrjxWw==", + "version": "5.31.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.31.0.tgz", + "integrity": "sha512-ZK0jVxSjS4gnPirpVjXHz7mgdOsZUHzNYSfTw2yPa3agfbt9YfqaBiBZFSSxeBWnpWkzCxTfUpnzA3Vily/CSg==", "dependencies": { - "@typescript-eslint/types": "5.30.7", + "@typescript-eslint/types": "5.31.0", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -16726,20 +16726,20 @@ } }, "node_modules/@vue/cli-plugin-eslint/node_modules/webpack": { - "version": "5.73.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.73.0.tgz", - "integrity": "sha512-svjudQRPPa0YiOYa2lM/Gacw0r6PvxptHj4FuEKQ2kX05ZLkjbVc5MnPs6its5j7IZljnIqSVo/OsY2X0IpHGA==", + "version": "5.74.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz", + "integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==", "dependencies": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^0.0.51", "@webassemblyjs/ast": "1.11.1", "@webassemblyjs/wasm-edit": "1.11.1", "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.4.1", + "acorn": "^8.7.1", "acorn-import-assertions": "^1.7.6", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.9.3", + "enhanced-resolve": "^5.10.0", "es-module-lexer": "^0.9.0", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -16752,7 +16752,7 @@ "schema-utils": "^3.1.0", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.3.1", + "watchpack": "^2.4.0", "webpack-sources": "^3.2.3" }, "bin": { @@ -21338,9 +21338,9 @@ } }, "node_modules/ast-types": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.14.2.tgz", - "integrity": "sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==", + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", "dependencies": { "tslib": "^2.0.1" }, @@ -21506,9 +21506,9 @@ } }, "node_modules/aws-sdk": { - "version": "2.1181.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1181.0.tgz", - "integrity": "sha512-AAHSknRFAIjXBA/XNAL7gS79agr1LbS0oGimOJqJauGSJfWNaOpDc7z6OLNUQqGa5Joc3maD5QJcSKp1Pm/deQ==", + "version": "2.1182.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1182.0.tgz", + "integrity": "sha512-iemVvLTc2iy0rz3xTp8zc/kD27gIfDF/mk6bxY8/35xMulKCVANWUkAH8jWRKReHh5F/gX4bp33dnfG63ny1Ww==", "dependencies": { "buffer": "4.9.2", "events": "1.1.1", @@ -23054,6 +23054,11 @@ "file-uri-to-path": "1.0.0" } }, + "node_modules/bindings/node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + }, "node_modules/bintrees": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.2.tgz", @@ -23451,9 +23456,9 @@ } }, "node_modules/browserslist": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.2.tgz", - "integrity": "sha512-MonuOgAtUB46uP5CezYbRaYKBNt2LxP0yX+Pmj4LkcDFGkn9Cbpi83d9sCjwQDErXsIJSzY5oKGDbgOlF/LPAA==", + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.3.tgz", + "integrity": "sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==", "funding": [ { "type": "opencollective", @@ -23465,10 +23470,10 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001366", - "electron-to-chromium": "^1.4.188", + "caniuse-lite": "^1.0.30001370", + "electron-to-chromium": "^1.4.202", "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.4" + "update-browserslist-db": "^1.0.5" }, "bin": { "browserslist": "cli.js" @@ -24083,9 +24088,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001369", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001369.tgz", - "integrity": "sha512-OY1SBHaodJc4wflDIKnlkdqWzJZd1Ls/2zbVJHBSv3AT7vgOJ58yAhd2CN4d57l2kPJrgMb7P9+N1Mhy4tNSQA==", + "version": "1.0.30001370", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001370.tgz", + "integrity": "sha512-3PDmaP56wz/qz7G508xzjx8C+MC2qEm4SYhSEzC9IBROo+dGXFWRuaXkWti0A9tuI00g+toiriVqxtWMgl350g==", "funding": [ { "type": "opencollective", @@ -24681,9 +24686,9 @@ } }, "node_modules/cli-spinners": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", - "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz", + "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==", "engines": { "node": ">=6" }, @@ -26658,6 +26663,11 @@ "node": ">=0.10.0" } }, + "node_modules/copy-to": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/copy-to/-/copy-to-2.0.1.tgz", + "integrity": "sha512-3DdaFaU/Zf1AnpLiFDeNCD4TOWe3Zl2RZaTzUvWiIk5ERzcCodOE20Vqq4fzCbNoHURFHT4/us/Lfq+S2zyY4w==" + }, "node_modules/copy-webpack-plugin": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.1.2.tgz", @@ -26895,9 +26905,9 @@ } }, "node_modules/core-js": { - "version": "3.23.5", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.23.5.tgz", - "integrity": "sha512-7Vh11tujtAZy82da4duVreQysIoO2EvVrur7y6IzZkH1IHPSekuDi8Vuw1+YKjkbfWLRD7Nc9ICQ/sIUDutcyg==", + "version": "3.24.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.24.0.tgz", + "integrity": "sha512-IeOyT8A6iK37Ep4kZDD423mpi6JfPRoPUdQwEWYiGolvn4o6j2diaRzNfDfpTdu3a5qMbrGUzKUpYpRY8jXCkQ==", "hasInstallScript": true, "funding": { "type": "opencollective", @@ -26905,9 +26915,9 @@ } }, "node_modules/core-js-compat": { - "version": "3.23.5", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.23.5.tgz", - "integrity": "sha512-fHYozIFIxd+91IIbXJgWd/igXIc8Mf9is0fusswjnGIWVG96y2cwyUdlCkGOw6rMLHKAxg7xtCIVaHsyOUnJIg==", + "version": "3.24.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.24.0.tgz", + "integrity": "sha512-F+2E63X3ff/nj8uIrf8Rf24UDGIz7p838+xjEp+Bx3y8OWXj+VTPPZNCtdqovPaS9o7Tka5mCH01Zn5vOd6UQg==", "dependencies": { "browserslist": "^4.21.2", "semver": "7.0.0" @@ -26926,9 +26936,9 @@ } }, "node_modules/core-js-pure": { - "version": "3.23.5", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.23.5.tgz", - "integrity": "sha512-8t78LdpKSuCq4pJYCYk8hl7XEkAX+BP16yRIwL3AanTksxuEf7CM83vRyctmiEL8NDZ3jpUcv56fk9/zG3aIuw==", + "version": "3.24.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.24.0.tgz", + "integrity": "sha512-uzMmW8cRh7uYw4JQtzqvGWRyC2T5+4zipQLQdi2FmiRqP83k3d6F3stv2iAlNhOs6cXN401FCD5TL0vvleuHgA==", "hasInstallScript": true, "funding": { "type": "opencollective", @@ -27842,6 +27852,14 @@ "node": ">=0.10" } }, + "node_modules/data-uri-to-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz", + "integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==", + "engines": { + "node": ">= 6" + } + }, "node_modules/data-urls": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", @@ -28418,6 +28436,32 @@ "node": ">= 0.10" } }, + "node_modules/default-user-agent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/default-user-agent/-/default-user-agent-1.0.0.tgz", + "integrity": "sha512-bDF7bg6OSNcSwFWPu4zYKpVkJZQYVrAANMYB8bc9Szem1D0yKdm4sa/rOCs2aC9+2GMqQ7KnwtZRvDhmLF0dXw==", + "dependencies": { + "os-name": "~1.0.3" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/default-user-agent/node_modules/os-name": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/os-name/-/os-name-1.0.3.tgz", + "integrity": "sha512-f5estLO2KN8vgtTRaILIgEGBoBrMnZ3JQ7W9TMZCnOIGwHe8TRGSpcagnWDo+Dfhd/z08k9Xe75hvciJJ8Qaew==", + "dependencies": { + "osx-release": "^1.0.0", + "win-release": "^1.0.0" + }, + "bin": { + "os-name": "cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/defaults": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", @@ -28469,6 +28513,96 @@ "node": ">=0.10.0" } }, + "node_modules/degenerator": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-3.0.2.tgz", + "integrity": "sha512-c0mef3SNQo56t6urUU6tdQAs+ThoD0o9B9MJ8HEt7NQcGEILCRFqQb7ZbP9JAv+QF1Ky5plydhMR/IrqWDm+TQ==", + "dependencies": { + "ast-types": "^0.13.2", + "escodegen": "^1.8.1", + "esprima": "^4.0.0", + "vm2": "^3.9.8" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/degenerator/node_modules/escodegen": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=4.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/degenerator/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/degenerator/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/degenerator/node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/degenerator/node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/degenerator/node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/del": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", @@ -28807,6 +28941,28 @@ "node": "*" } }, + "node_modules/digest-header": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/digest-header/-/digest-header-0.0.1.tgz", + "integrity": "sha512-Qi0KOZgRnkQJuvMWbs1ZRRajEnbsMU8xlJI4rHIbPC+skHQ30heO5cIHpUFT4jAvAe+zPtdavLSAxASqoyZ3cg==", + "dependencies": { + "utility": "0.1.11" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/digest-header/node_modules/utility": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/utility/-/utility-0.1.11.tgz", + "integrity": "sha512-epFsJ71+/yC7MKMX7CM9azP31QBIQhywkiBUj74i/T3Y2TXtEor26QBkat7lGamrrNTr5CBI1imd/8F0Bmqw4g==", + "dependencies": { + "address": ">=0.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -29162,9 +29318,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.199", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.199.tgz", - "integrity": "sha512-WIGME0Cs7oob3mxsJwHbeWkH0tYkIE/sjkJ8ML2BYmuRcjhRl/q5kVDXG7W9LOOKwzPU5M0LBlXRq9rlSgnNlg==" + "version": "1.4.202", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.202.tgz", + "integrity": "sha512-JYsK2ex9lmQD27kj19fhXYxzFJ/phLAkLKHv49A5UY6kMRV2xED3qMMLg/voW/+0AR6wMiI+VxlmK9NDtdxlPA==" }, "node_modules/element-ui": { "version": "2.15.9", @@ -29557,9 +29713,9 @@ } }, "node_modules/esbuild": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.49.tgz", - "integrity": "sha512-/TlVHhOaq7Yz8N1OJrjqM3Auzo5wjvHFLk+T8pIue+fhnhIMpfAzsG6PLVMbFveVxqD2WOp3QHei+52IMUNmCw==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.50.tgz", + "integrity": "sha512-SbC3k35Ih2IC6trhbMYW7hYeGdjPKf9atTKwBUHqMCYFZZ9z8zhuvfnZihsnJypl74FjiAKjBRqFkBkAd0rS/w==", "hasInstallScript": true, "bin": { "esbuild": "bin/esbuild" @@ -29568,32 +29724,32 @@ "node": ">=12" }, "optionalDependencies": { - "esbuild-android-64": "0.14.49", - "esbuild-android-arm64": "0.14.49", - "esbuild-darwin-64": "0.14.49", - "esbuild-darwin-arm64": "0.14.49", - "esbuild-freebsd-64": "0.14.49", - "esbuild-freebsd-arm64": "0.14.49", - "esbuild-linux-32": "0.14.49", - "esbuild-linux-64": "0.14.49", - "esbuild-linux-arm": "0.14.49", - "esbuild-linux-arm64": "0.14.49", - "esbuild-linux-mips64le": "0.14.49", - "esbuild-linux-ppc64le": "0.14.49", - "esbuild-linux-riscv64": "0.14.49", - "esbuild-linux-s390x": "0.14.49", - "esbuild-netbsd-64": "0.14.49", - "esbuild-openbsd-64": "0.14.49", - "esbuild-sunos-64": "0.14.49", - "esbuild-windows-32": "0.14.49", - "esbuild-windows-64": "0.14.49", - "esbuild-windows-arm64": "0.14.49" + "esbuild-android-64": "0.14.50", + "esbuild-android-arm64": "0.14.50", + "esbuild-darwin-64": "0.14.50", + "esbuild-darwin-arm64": "0.14.50", + "esbuild-freebsd-64": "0.14.50", + "esbuild-freebsd-arm64": "0.14.50", + "esbuild-linux-32": "0.14.50", + "esbuild-linux-64": "0.14.50", + "esbuild-linux-arm": "0.14.50", + "esbuild-linux-arm64": "0.14.50", + "esbuild-linux-mips64le": "0.14.50", + "esbuild-linux-ppc64le": "0.14.50", + "esbuild-linux-riscv64": "0.14.50", + "esbuild-linux-s390x": "0.14.50", + "esbuild-netbsd-64": "0.14.50", + "esbuild-openbsd-64": "0.14.50", + "esbuild-sunos-64": "0.14.50", + "esbuild-windows-32": "0.14.50", + "esbuild-windows-64": "0.14.50", + "esbuild-windows-arm64": "0.14.50" } }, "node_modules/esbuild-android-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.49.tgz", - "integrity": "sha512-vYsdOTD+yi+kquhBiFWl3tyxnj2qZJsl4tAqwhT90ktUdnyTizgle7TjNx6Ar1bN7wcwWqZ9QInfdk2WVagSww==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.50.tgz", + "integrity": "sha512-H7iUEm7gUJHzidsBlFPGF6FTExazcgXL/46xxLo6i6bMtPim6ZmXyTccS8yOMpy6HAC6dPZ/JCQqrkkin69n6Q==", "cpu": [ "x64" ], @@ -29606,9 +29762,9 @@ } }, "node_modules/esbuild-android-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.49.tgz", - "integrity": "sha512-g2HGr/hjOXCgSsvQZ1nK4nW/ei8JUx04Li74qub9qWrStlysaVmadRyTVuW32FGIpLQyc5sUjjZopj49eGGM2g==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.50.tgz", + "integrity": "sha512-NFaoqEwa+OYfoYVpQWDMdKII7wZZkAjtJFo1WdnBeCYlYikvUhTnf2aPwPu5qEAw/ie1NYK0yn3cafwP+kP+OQ==", "cpu": [ "arm64" ], @@ -29621,9 +29777,9 @@ } }, "node_modules/esbuild-darwin-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.49.tgz", - "integrity": "sha512-3rvqnBCtX9ywso5fCHixt2GBCUsogNp9DjGmvbBohh31Ces34BVzFltMSxJpacNki96+WIcX5s/vum+ckXiLYg==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.50.tgz", + "integrity": "sha512-gDQsCvGnZiJv9cfdO48QqxkRV8oKAXgR2CGp7TdIpccwFdJMHf8hyIJhMW/05b/HJjET/26Us27Jx91BFfEVSA==", "cpu": [ "x64" ], @@ -29636,9 +29792,9 @@ } }, "node_modules/esbuild-darwin-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.49.tgz", - "integrity": "sha512-XMaqDxO846srnGlUSJnwbijV29MTKUATmOLyQSfswbK/2X5Uv28M9tTLUJcKKxzoo9lnkYPsx2o8EJcTYwCs/A==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.50.tgz", + "integrity": "sha512-36nNs5OjKIb/Q50Sgp8+rYW/PqirRiFN0NFc9hEvgPzNJxeJedktXwzfJSln4EcRFRh5Vz4IlqFRScp+aiBBzA==", "cpu": [ "arm64" ], @@ -29651,9 +29807,9 @@ } }, "node_modules/esbuild-freebsd-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.49.tgz", - "integrity": "sha512-NJ5Q6AjV879mOHFri+5lZLTp5XsO2hQ+KSJYLbfY9DgCu8s6/Zl2prWXVANYTeCDLlrIlNNYw8y34xqyLDKOmQ==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.50.tgz", + "integrity": "sha512-/1pHHCUem8e/R86/uR+4v5diI2CtBdiWKiqGuPa9b/0x3Nwdh5AOH7lj+8823C6uX1e0ufwkSLkS+aFZiBCWxA==", "cpu": [ "x64" ], @@ -29666,9 +29822,9 @@ } }, "node_modules/esbuild-freebsd-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.49.tgz", - "integrity": "sha512-lFLtgXnAc3eXYqj5koPlBZvEbBSOSUbWO3gyY/0+4lBdRqELyz4bAuamHvmvHW5swJYL7kngzIZw6kdu25KGOA==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.50.tgz", + "integrity": "sha512-iKwUVMQztnPZe5pUYHdMkRc9aSpvoV1mkuHlCoPtxZA3V+Kg/ptpzkcSY+fKd0kuom+l6Rc93k0UPVkP7xoqrw==", "cpu": [ "arm64" ], @@ -29681,9 +29837,9 @@ } }, "node_modules/esbuild-linux-32": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.49.tgz", - "integrity": "sha512-zTTH4gr2Kb8u4QcOpTDVn7Z8q7QEIvFl/+vHrI3cF6XOJS7iEI1FWslTo3uofB2+mn6sIJEQD9PrNZKoAAMDiA==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.50.tgz", + "integrity": "sha512-sWUwvf3uz7dFOpLzYuih+WQ7dRycrBWHCdoXJ4I4XdMxEHCECd8b7a9N9u7FzT6XR2gHPk9EzvchQUtiEMRwqw==", "cpu": [ "ia32" ], @@ -29696,9 +29852,9 @@ } }, "node_modules/esbuild-linux-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.49.tgz", - "integrity": "sha512-hYmzRIDzFfLrB5c1SknkxzM8LdEUOusp6M2TnuQZJLRtxTgyPnZZVtyMeCLki0wKgYPXkFsAVhi8vzo2mBNeTg==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.50.tgz", + "integrity": "sha512-u0PQxPhaeI629t4Y3EEcQ0wmWG+tC/LpP2K7yDFvwuPq0jSQ8SIN+ARNYfRjGW15O2we3XJvklbGV0wRuUCPig==", "cpu": [ "x64" ], @@ -29711,9 +29867,9 @@ } }, "node_modules/esbuild-linux-arm": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.49.tgz", - "integrity": "sha512-iE3e+ZVv1Qz1Sy0gifIsarJMQ89Rpm9mtLSRtG3AH0FPgAzQ5Z5oU6vYzhc/3gSPi2UxdCOfRhw2onXuFw/0lg==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.50.tgz", + "integrity": "sha512-VALZq13bhmFJYFE/mLEb+9A0w5vo8z+YDVOWeaf9vOTrSC31RohRIwtxXBnVJ7YKLYfEMzcgFYf+OFln3Y0cWg==", "cpu": [ "arm" ], @@ -29726,9 +29882,9 @@ } }, "node_modules/esbuild-linux-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.49.tgz", - "integrity": "sha512-KLQ+WpeuY+7bxukxLz5VgkAAVQxUv67Ft4DmHIPIW+2w3ObBPQhqNoeQUHxopoW/aiOn3m99NSmSV+bs4BSsdA==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.50.tgz", + "integrity": "sha512-ZyfoNgsTftD7Rp5S7La5auomKdNeB3Ck+kSKXC4pp96VnHyYGjHHXWIlcbH8i+efRn9brszo1/Thl1qn8RqmhQ==", "cpu": [ "arm64" ], @@ -29741,9 +29897,9 @@ } }, "node_modules/esbuild-linux-mips64le": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.49.tgz", - "integrity": "sha512-n+rGODfm8RSum5pFIqFQVQpYBw+AztL8s6o9kfx7tjfK0yIGF6tm5HlG6aRjodiiKkH2xAiIM+U4xtQVZYU4rA==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.50.tgz", + "integrity": "sha512-ygo31Vxn/WrmjKCHkBoutOlFG5yM9J2UhzHb0oWD9O61dGg+Hzjz9hjf5cmM7FBhAzdpOdEWHIrVOg2YAi6rTw==", "cpu": [ "mips64el" ], @@ -29756,9 +29912,9 @@ } }, "node_modules/esbuild-linux-ppc64le": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.49.tgz", - "integrity": "sha512-WP9zR4HX6iCBmMFH+XHHng2LmdoIeUmBpL4aL2TR8ruzXyT4dWrJ5BSbT8iNo6THN8lod6GOmYDLq/dgZLalGw==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.50.tgz", + "integrity": "sha512-xWCKU5UaiTUT6Wz/O7GKP9KWdfbsb7vhfgQzRfX4ahh5NZV4ozZ4+SdzYG8WxetsLy84UzLX3Pi++xpVn1OkFQ==", "cpu": [ "ppc64" ], @@ -29771,9 +29927,9 @@ } }, "node_modules/esbuild-linux-riscv64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.49.tgz", - "integrity": "sha512-h66ORBz+Dg+1KgLvzTVQEA1LX4XBd1SK0Fgbhhw4akpG/YkN8pS6OzYI/7SGENiN6ao5hETRDSkVcvU9NRtkMQ==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.50.tgz", + "integrity": "sha512-0+dsneSEihZTopoO9B6Z6K4j3uI7EdxBP7YSF5rTwUgCID+wHD3vM1gGT0m+pjCW+NOacU9kH/WE9N686FHAJg==", "cpu": [ "riscv64" ], @@ -29786,9 +29942,9 @@ } }, "node_modules/esbuild-linux-s390x": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.49.tgz", - "integrity": "sha512-DhrUoFVWD+XmKO1y7e4kNCqQHPs6twz6VV6Uezl/XHYGzM60rBewBF5jlZjG0nCk5W/Xy6y1xWeopkrhFFM0sQ==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.50.tgz", + "integrity": "sha512-tVjqcu8o0P9H4StwbIhL1sQYm5mWATlodKB6dpEZFkcyTI8kfIGWiWcrGmkNGH2i1kBUOsdlBafPxR3nzp3TDA==", "cpu": [ "s390x" ], @@ -29801,9 +29957,9 @@ } }, "node_modules/esbuild-netbsd-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.49.tgz", - "integrity": "sha512-BXaUwFOfCy2T+hABtiPUIpWjAeWK9P8O41gR4Pg73hpzoygVGnj0nI3YK4SJhe52ELgtdgWP/ckIkbn2XaTxjQ==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.50.tgz", + "integrity": "sha512-0R/glfqAQ2q6MHDf7YJw/TulibugjizBxyPvZIcorH0Mb7vSimdHy0XF5uCba5CKt+r4wjax1mvO9lZ4jiAhEg==", "cpu": [ "x64" ], @@ -29816,9 +29972,9 @@ } }, "node_modules/esbuild-openbsd-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.49.tgz", - "integrity": "sha512-lP06UQeLDGmVPw9Rg437Btu6J9/BmyhdoefnQ4gDEJTtJvKtQaUcOQrhjTq455ouZN4EHFH1h28WOJVANK41kA==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.50.tgz", + "integrity": "sha512-7PAtmrR5mDOFubXIkuxYQ4bdNS6XCK8AIIHUiZxq1kL8cFIH5731jPcXQ4JNy/wbj1C9sZ8rzD8BIM80Tqk29w==", "cpu": [ "x64" ], @@ -29831,9 +29987,9 @@ } }, "node_modules/esbuild-sunos-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.49.tgz", - "integrity": "sha512-4c8Zowp+V3zIWje329BeLbGh6XI9c/rqARNaj5yPHdC61pHI9UNdDxT3rePPJeWcEZVKjkiAS6AP6kiITp7FSw==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.50.tgz", + "integrity": "sha512-gBxNY/wyptvD7PkHIYcq7se6SQEXcSC8Y7mE0FJB+CGgssEWf6vBPfTTZ2b6BWKnmaP6P6qb7s/KRIV5T2PxsQ==", "cpu": [ "x64" ], @@ -29846,9 +30002,9 @@ } }, "node_modules/esbuild-windows-32": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.49.tgz", - "integrity": "sha512-q7Rb+J9yHTeKr9QTPDYkqfkEj8/kcKz9lOabDuvEXpXuIcosWCJgo5Z7h/L4r7rbtTH4a8U2FGKb6s1eeOHmJA==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.50.tgz", + "integrity": "sha512-MOOe6J9cqe/iW1qbIVYSAqzJFh0p2LBLhVUIWdMVnNUNjvg2/4QNX4oT4IzgDeldU+Bym9/Tn6+DxvUHJXL5Zw==", "cpu": [ "ia32" ], @@ -29861,9 +30017,9 @@ } }, "node_modules/esbuild-windows-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.49.tgz", - "integrity": "sha512-+Cme7Ongv0UIUTniPqfTX6mJ8Deo7VXw9xN0yJEN1lQMHDppTNmKwAM3oGbD/Vqff+07K2gN0WfNkMohmG+dVw==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.50.tgz", + "integrity": "sha512-r/qE5Ex3w1jjGv/JlpPoWB365ldkppUlnizhMxJgojp907ZF1PgLTuW207kgzZcSCXyquL9qJkMsY+MRtaZ5yQ==", "cpu": [ "x64" ], @@ -29876,9 +30032,9 @@ } }, "node_modules/esbuild-windows-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.49.tgz", - "integrity": "sha512-v+HYNAXzuANrCbbLFJ5nmO3m5y2PGZWLe3uloAkLt87aXiO2mZr3BTmacZdjwNkNEHuH3bNtN8cak+mzVjVPfA==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.50.tgz", + "integrity": "sha512-EMS4lQnsIe12ZyAinOINx7eq2mjpDdhGZZWDwPZE/yUTN9cnc2Ze/xUTYIAyaJqrqQda3LnDpADKpvLvol6ENQ==", "cpu": [ "arm64" ], @@ -30499,9 +30655,9 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/eslint-plugin-n8n-nodes-base": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-n8n-nodes-base/-/eslint-plugin-n8n-nodes-base-1.5.4.tgz", - "integrity": "sha512-w2anVulKpvNWrFVYtoPsGmMiJFFLiWJWiRVYKR29drRINEwII7YgyLeqjWkzYy/3y+u/l1hwr2Oh8RwDznoO4Q==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-n8n-nodes-base/-/eslint-plugin-n8n-nodes-base-1.5.5.tgz", + "integrity": "sha512-ZstoBrGzbsed/YssCWL4R8uRnH2T4qyox6cdyo2ICLhX3TSB9EIMIndo+D/+YWXEon6pX8r9MBgkIb+Q+LSXTg==", "dependencies": { "@typescript-eslint/utils": "^5.17.0", "camel-case": "^4.1.2", @@ -31697,9 +31853,12 @@ } }, "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz", + "integrity": "sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg==", + "engines": { + "node": ">= 6" + } }, "node_modules/filelist": { "version": "1.0.4", @@ -32523,6 +32682,27 @@ "url": "https://ko-fi.com/tunnckoCore/commissions" } }, + "node_modules/formstream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/formstream/-/formstream-1.1.1.tgz", + "integrity": "sha512-yHRxt3qLFnhsKAfhReM4w17jP+U1OlhUjnKPPtonwKbIJO7oBP0MvoxkRUwb8AU9n0MIkYy5X5dK6pQnbj+R2Q==", + "dependencies": { + "destroy": "^1.0.4", + "mime": "^2.5.2", + "pause-stream": "~0.0.11" + } + }, + "node_modules/formstream/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -32673,6 +32853,18 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/ftp": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", + "integrity": "sha512-faFVML1aBx2UoDStmLwv2Wptt4vw5x03xxX172nhA5Y5HBshW5JweqQ2W4xL4dezQTG8inJsuYcpPHHU3X5OTQ==", + "dependencies": { + "readable-stream": "1.1.x", + "xregexp": "2.0.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -33106,6 +33298,59 @@ "node": ">8.0.0" } }, + "node_modules/get-uri": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-3.0.2.tgz", + "integrity": "sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg==", + "dependencies": { + "@tootallnate/once": "1", + "data-uri-to-buffer": "3", + "debug": "4", + "file-uri-to-path": "2", + "fs-extra": "^8.1.0", + "ftp": "^0.3.10" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/get-uri/node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/get-uri/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/get-uri/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/get-uri/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", @@ -36015,7 +36260,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", - "devOptional": true, "dependencies": { "ms": "^2.0.0" } @@ -43139,9 +43383,9 @@ } }, "node_modules/libphonenumber-js": { - "version": "1.10.9", - "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.9.tgz", - "integrity": "sha512-BvPlectKyHuA8xVBU4PerKdI1t+l71F/GCh6CQhe4j5bTwibF6Jcle88kDcyvq4aW55CXxWZg7yIYhzmjgrjkQ==" + "version": "1.10.10", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.10.tgz", + "integrity": "sha512-JzYUapWcHkUe5n6OFqxJtHfCfuU0juqkqc9P+hrfzgmJODaREYLUgceiNAmIGx5j3Gjp7KVxi3koFo7OJFSTxg==" }, "node_modules/libqp": { "version": "1.1.0", @@ -45508,6 +45752,14 @@ "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz", "integrity": "sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==" }, + "node_modules/netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/next-tick": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", @@ -47049,6 +47301,20 @@ "os-tmpdir": "^1.0.0" } }, + "node_modules/osx-release": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/osx-release/-/osx-release-1.1.0.tgz", + "integrity": "sha512-ixCMMwnVxyHFQLQnINhmIpWqXIfS2YOXchwQrk+OFzmo6nDjQ0E4KXAyyUh0T0MZgV4bUhkRrAbVqlE4yLVq4A==", + "dependencies": { + "minimist": "^1.1.0" + }, + "bin": { + "osx-release": "cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/p-all": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/p-all/-/p-all-2.1.0.tgz", @@ -47278,6 +47544,77 @@ "node": ">=4" } }, + "node_modules/pac-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-5.0.0.tgz", + "integrity": "sha512-CcFG3ZtnxO8McDigozwE3AqAw15zDvGH+OjXO4kzf7IkEKkQ4gxQ+3sdF50WmhQ4P/bVusXcqNE2S3XrNURwzQ==", + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4", + "get-uri": "3", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "5", + "pac-resolver": "^5.0.0", + "raw-body": "^2.2.0", + "socks-proxy-agent": "5" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/pac-proxy-agent/node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pac-proxy-agent/node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pac-proxy-agent/node_modules/socks-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz", + "integrity": "sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==", + "dependencies": { + "agent-base": "^6.0.2", + "debug": "4", + "socks": "^2.3.3" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pac-resolver": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-5.0.1.tgz", + "integrity": "sha512-cy7u00ko2KVgBAjuhevqpPeHIkCIqPe1v24cydhWjmeuzaBfmUWFCZJ1iAh5TuVzVZoUzXIW7K8sMYOZ84uZ9Q==", + "dependencies": { + "degenerator": "^3.0.2", + "ip": "^1.1.5", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/pac-resolver/node_modules/ip": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", + "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==" + }, "node_modules/packet-reader": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", @@ -47503,14 +47840,14 @@ "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==" }, "node_modules/parse-url": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-6.0.2.tgz", - "integrity": "sha512-uCSjOvD3T+6B/sPWhR+QowAZcU/o4bjPrVBQBGFxcDF6J6FraCGIaDBsdoQawiaaAVdHvtqBe3w3vKlfBKySOQ==", + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-6.0.5.tgz", + "integrity": "sha512-e35AeLTSIlkw/5GFq70IN7po8fmDUjpDPY1rIK+VubRfsUvBonjQ+PBZG+vWMACnQSmNlvl524IucoDmcioMxA==", "dev": true, "dependencies": { "is-ssh": "^1.3.0", "normalize-url": "^6.1.0", - "parse-path": "^4.0.4", + "parse-path": "^4.0.0", "protocols": "^1.4.0" } }, @@ -47812,6 +48149,14 @@ "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" }, + "node_modules/pause-stream": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==", + "dependencies": { + "through": "~2.3" + } + }, "node_modules/pbkdf2": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", @@ -49320,6 +49665,58 @@ "node": ">= 0.10" } }, + "node_modules/proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-5.0.0.tgz", + "integrity": "sha512-gkH7BkvLVkSfX9Dk27W6TyNOWWZWRilRfk1XxGNWOYJ2TuedAv1yFpCaU9QSBmBe716XOTNpYNOzhysyw8xn7g==", + "dependencies": { + "agent-base": "^6.0.0", + "debug": "4", + "http-proxy-agent": "^4.0.0", + "https-proxy-agent": "^5.0.0", + "lru-cache": "^5.1.1", + "pac-proxy-agent": "^5.0.0", + "proxy-from-env": "^1.0.0", + "socks-proxy-agent": "^5.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/proxy-agent/node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/proxy-agent/node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/proxy-agent/node_modules/socks-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz", + "integrity": "sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==", + "dependencies": { + "agent-base": "^6.0.2", + "debug": "4", + "socks": "^2.3.3" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -50488,6 +50885,17 @@ "node": ">= 4" } }, + "node_modules/recast/node_modules/ast-types": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.14.2.tgz", + "integrity": "sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/recast/node_modules/tslib": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", @@ -51251,18 +51659,6 @@ "uuid": "bin/uuid" } }, - "node_modules/requestretry": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/requestretry/-/requestretry-7.1.0.tgz", - "integrity": "sha512-TqVDgp251BW4b8ddQ2ptaj/57Z3LZHLscAUT7v6qs70buqF2/IoOVjYbpjJ6HiW7j5+waqegGI8xKJ/+uzgDmw==", - "dependencies": { - "extend": "^3.0.2", - "lodash": "^4.17.15" - }, - "peerDependencies": { - "request": "2.*.*" - } - }, "node_modules/require-at": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/require-at/-/require-at-1.0.6.tgz", @@ -51472,9 +51868,9 @@ "integrity": "sha512-fJhQQI5tLrQvYIYFpOnFinzv9dwmR7hRnUz1XqP3OJ1jIweTNOd6aTO4jwQSgcBSFUB+/KHJxuGneime+FdzOw==" }, "node_modules/rollup": { - "version": "2.77.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.77.0.tgz", - "integrity": "sha512-vL8xjY4yOQEw79DvyXLijhnhh+R/O9zpF/LEgkCebZFtb6ELeN9H3/2T0r8+mp+fFTBHZ5qGpOpW2ela2zRt3g==", + "version": "2.77.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.77.2.tgz", + "integrity": "sha512-m/4YzYgLcpMQbxX3NmAqDvwLATZzxt8bIegO78FZLl+lAgKJBd1DRAOeEiZcKOIOPjxE6ewHWHNgGEalFXuz1g==", "bin": { "rollup": "dist/bin/rollup" }, @@ -52487,7 +52883,6 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "devOptional": true, "engines": { "node": ">= 6.0.0", "npm": ">= 3.0.0" @@ -52701,9 +53096,9 @@ } }, "node_modules/snowflake-sdk": { - "version": "1.6.11", - "resolved": "https://registry.npmjs.org/snowflake-sdk/-/snowflake-sdk-1.6.11.tgz", - "integrity": "sha512-w4oCXjNQ1peAJjhnrwihr+epYw1pSxbe5/+PdxexYb2rzowyOn0RA5PFbir90q/dx0jzM2gvPiHDjnSBEZ1/zA==", + "version": "1.6.12", + "resolved": "https://registry.npmjs.org/snowflake-sdk/-/snowflake-sdk-1.6.12.tgz", + "integrity": "sha512-nkwtsWsZr4KrloLgpMpLgCnJIxfcuWlD4sqR53kn8BQRmhOi6cSBgnvZmoYcFvW2arVvfHh/Dc3vOQ/4OuRSLg==", "dependencies": { "@azure/storage-blob": "^12.5.0", "@techteamer/ocsp": "1.0.0", @@ -52729,12 +53124,11 @@ "moment-timezone": "^0.5.15", "open": "^7.3.1", "python-struct": "^1.1.3", - "request": "^2.88.2", - "requestretry": "^7.0.1", "simple-lru-cache": "^0.0.2", "string-similarity": "^4.0.4", "test-console": "^2.0.0", "tmp": "^0.2.1", + "urllib": "^2.38.0", "uuid": "^3.3.2", "winston": "^3.1.0" } @@ -52827,7 +53221,6 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/socks/-/socks-2.3.3.tgz", "integrity": "sha512-o5t52PCNtVdiOvzMry7wU4aOqYWL0PeCXRWBEiJow4/i/wr+wpsJQ9awEu1EonLIqsfGd5qSgDdxEOvCdmBEpA==", - "dev": true, "dependencies": { "ip": "1.1.5", "smart-buffer": "^4.1.0" @@ -52865,8 +53258,7 @@ "node_modules/socks/node_modules/ip": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha512-rBtCAQAJm8A110nbwn6YdveUnuZH3WrC36IwkRXxDnq53JvXA2NVQvB7IHyKomxK1MJ4VDNw3UtFDdXQ+AvLYA==", - "dev": true + "integrity": "sha512-rBtCAQAJm8A110nbwn6YdveUnuZH3WrC36IwkRXxDnq53JvXA2NVQvB7IHyKomxK1MJ4VDNw3UtFDdXQ+AvLYA==" }, "node_modules/sort-keys": { "version": "1.1.2", @@ -56732,9 +57124,9 @@ "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" }, "node_modules/uglify-js": { - "version": "3.16.2", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.16.2.tgz", - "integrity": "sha512-AaQNokTNgExWrkEYA24BTNMSjyqEXPSfhqoS0AxmHkCJ4U+Dyy5AvbGV/sqxuxficEfGGoX3zWw9R7QpLFfEsg==", + "version": "3.16.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.16.3.tgz", + "integrity": "sha512-uVbFqx9vvLhQg0iBaau9Z75AxWJ8tqM9AV890dIZCLApF4rTcyHwmAvLeEdYRs+BzYWu8Iw81F79ah0EfTXbaw==", "optional": true, "bin": { "uglifyjs": "bin/uglifyjs" @@ -57364,6 +57756,68 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" }, + "node_modules/urllib": { + "version": "2.38.1", + "resolved": "https://registry.npmjs.org/urllib/-/urllib-2.38.1.tgz", + "integrity": "sha512-1tvjdL74oT9aV4X+SIjE1BXyes5PbfhHKhK4IlhoKhKqk4nD5/lXE90v10WZ02kELWIPI4w7ADneEQ4i7dPjiQ==", + "dependencies": { + "any-promise": "^1.3.0", + "content-type": "^1.0.2", + "debug": "^2.6.9", + "default-user-agent": "^1.0.0", + "digest-header": "^0.0.1", + "ee-first": "~1.1.1", + "formstream": "^1.1.0", + "humanize-ms": "^1.2.0", + "iconv-lite": "^0.4.15", + "ip": "^1.1.5", + "proxy-agent": "^5.0.0", + "pump": "^3.0.0", + "qs": "^6.4.0", + "statuses": "^1.3.1", + "utility": "^1.16.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/urllib/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/urllib/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/urllib/node_modules/ip": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", + "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==" + }, + "node_modules/urllib/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/urllib/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", @@ -57440,6 +57894,21 @@ "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==" }, + "node_modules/utility": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/utility/-/utility-1.17.0.tgz", + "integrity": "sha512-KdVkF9An/0239BJ4+dqOa7NPrPIOeQE9AGfx0XS16O9DBiHNHRJMoeU5nL6pRGAkgJOqdOu8R4gBRcXnAocJKw==", + "dependencies": { + "copy-to": "^2.0.1", + "escape-html": "^1.0.3", + "mkdirp": "^0.5.1", + "mz": "^2.7.0", + "unescape": "^1.0.1" + }, + "engines": { + "node": ">= 0.12.0" + } + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -58030,6 +58499,17 @@ "vue-inbrowser-compiler-utils": "^4.44.23" } }, + "node_modules/vue-docgen-api/node_modules/ast-types": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.14.2.tgz", + "integrity": "sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/vue-docgen-api/node_modules/hash-sum": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", @@ -58044,6 +58524,11 @@ "yallist": "^2.1.2" } }, + "node_modules/vue-docgen-api/node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, "node_modules/vue-docgen-api/node_modules/yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", @@ -60416,6 +60901,25 @@ "node": ">=8" } }, + "node_modules/win-release": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/win-release/-/win-release-1.1.1.tgz", + "integrity": "sha512-iCRnKVvGxOQdsKhcQId2PXV1vV3J/sDPXKA4Oe9+Eti2nb2ESEsYHRYls/UjoUW3bIc5ZDO8dTH50A/5iVN+bw==", + "dependencies": { + "semver": "^5.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/win-release/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, "node_modules/windows-release": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-3.3.3.tgz", @@ -63123,17 +63627,17 @@ } }, "@fortawesome/free-regular-svg-icons": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.1.1.tgz", - "integrity": "sha512-xXiW7hcpgwmWtndKPOzG+43fPH7ZjxOaoeyooptSztGmJxCAflHZxXNK0GcT0uEsR4jTGQAfGklDZE5NHoBhKg==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.1.2.tgz", + "integrity": "sha512-xR4hA+tAwsaTHGfb+25H1gVU/aJ0Rzu+xIUfnyrhaL13yNQ7TWiI2RvzniAaB+VGHDU2a+Pk96Ve+pkN3/+TTQ==", "requires": { - "@fortawesome/fontawesome-common-types": "6.1.1" + "@fortawesome/fontawesome-common-types": "6.1.2" }, "dependencies": { "@fortawesome/fontawesome-common-types": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.1.1.tgz", - "integrity": "sha512-wVn5WJPirFTnzN6tR95abCx+ocH+3IFLXAgyavnf9hUmN0CfWoDjPT/BAWsUVwSlYYVBeCLJxaqi7ZGe4uSjBA==" + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.1.2.tgz", + "integrity": "sha512-wBaAPGz1Awxg05e0PBRkDRuTsy4B3dpBm+zreTTyd9TH4uUM27cAL4xWyWR0rLJCrRwzVsQ4hF3FvM6rqydKPA==" } } }, @@ -73089,9 +73593,9 @@ } }, "@types/express-serve-static-core": { - "version": "4.17.29", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.29.tgz", - "integrity": "sha512-uMd++6dMKS32EOuw1Uli3e3BPgdLIXmezcfHv7N4c1s3gkhikBplORPpMq3fuWkxncZN1reb16d5n8yhQ80x7Q==", + "version": "4.17.30", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.30.tgz", + "integrity": "sha512-gstzbTWro2/nFed1WXtf+TtrpwxH7Ggs4RLYTLbeVgIkUQOI3WG/JKjgeOU1zXDvezllupjrf8OPIdvTbIaVOQ==", "requires": { "@types/node": "*", "@types/qs": "*", @@ -73574,9 +74078,9 @@ } }, "@types/prettier": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.6.3.tgz", - "integrity": "sha512-ymZk3LEC/fsut+/Q5qejp6R9O1rMxz3XaRHDV6kX8MrGAhOSPqVARbDi+EZvInBpw+BnCX3TD240byVkOfQsHg==" + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.6.4.tgz", + "integrity": "sha512-fOwvpvQYStpb/zHMx0Cauwywu9yLDmzWiiQBC7gJyq5tYLUXFZvDG7VK1B7WBxxjBJNKFOZ0zLoOQn8vmATbhw==" }, "@types/pretty-hrtime": { "version": "1.0.1", @@ -73956,13 +74460,13 @@ "integrity": "sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw==" }, "@typescript-eslint/eslint-plugin": { - "version": "5.30.7", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.7.tgz", - "integrity": "sha512-l4L6Do+tfeM2OK0GJsU7TUcM/1oN/N25xHm3Jb4z3OiDU4Lj8dIuxX9LpVMS9riSXQs42D1ieX7b85/r16H9Fw==", + "version": "5.31.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.31.0.tgz", + "integrity": "sha512-VKW4JPHzG5yhYQrQ1AzXgVgX8ZAJEvCz0QI6mLRX4tf7rnFfh5D8SKm0Pq6w5PyNfAWJk6sv313+nEt3ohWMBQ==", "requires": { - "@typescript-eslint/scope-manager": "5.30.7", - "@typescript-eslint/type-utils": "5.30.7", - "@typescript-eslint/utils": "5.30.7", + "@typescript-eslint/scope-manager": "5.31.0", + "@typescript-eslint/type-utils": "5.31.0", + "@typescript-eslint/utils": "5.31.0", "debug": "^4.3.4", "functional-red-black-tree": "^1.0.1", "ignore": "^5.2.0", @@ -73995,47 +74499,47 @@ } }, "@typescript-eslint/parser": { - "version": "5.30.7", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.30.7.tgz", - "integrity": "sha512-Rg5xwznHWWSy7v2o0cdho6n+xLhK2gntImp0rJroVVFkcYFYQ8C8UJTSuTw/3CnExBmPjycjmUJkxVmjXsld6A==", + "version": "5.31.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.31.0.tgz", + "integrity": "sha512-UStjQiZ9OFTFReTrN+iGrC6O/ko9LVDhreEK5S3edmXgR396JGq7CoX2TWIptqt/ESzU2iRKXAHfSF2WJFcWHw==", "requires": { - "@typescript-eslint/scope-manager": "5.30.7", - "@typescript-eslint/types": "5.30.7", - "@typescript-eslint/typescript-estree": "5.30.7", + "@typescript-eslint/scope-manager": "5.31.0", + "@typescript-eslint/types": "5.31.0", + "@typescript-eslint/typescript-estree": "5.31.0", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "5.30.7", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.7.tgz", - "integrity": "sha512-7BM1bwvdF1UUvt+b9smhqdc/eniOnCKxQT/kj3oXtj3LqnTWCAM0qHRHfyzCzhEfWX0zrW7KqXXeE4DlchZBKw==", + "version": "5.31.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.31.0.tgz", + "integrity": "sha512-8jfEzBYDBG88rcXFxajdVavGxb5/XKXyvWgvD8Qix3EEJLCFIdVloJw+r9ww0wbyNLOTYyBsR+4ALNGdlalLLg==", "requires": { - "@typescript-eslint/types": "5.30.7", - "@typescript-eslint/visitor-keys": "5.30.7" + "@typescript-eslint/types": "5.31.0", + "@typescript-eslint/visitor-keys": "5.31.0" } }, "@typescript-eslint/type-utils": { - "version": "5.30.7", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.30.7.tgz", - "integrity": "sha512-nD5qAE2aJX/YLyKMvOU5jvJyku4QN5XBVsoTynFrjQZaDgDV6i7QHFiYCx10wvn7hFvfuqIRNBtsgaLe0DbWhw==", + "version": "5.31.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.31.0.tgz", + "integrity": "sha512-7ZYqFbvEvYXFn9ax02GsPcEOmuWNg+14HIf4q+oUuLnMbpJ6eHAivCg7tZMVwzrIuzX3QCeAOqKoyMZCv5xe+w==", "requires": { - "@typescript-eslint/utils": "5.30.7", + "@typescript-eslint/utils": "5.31.0", "debug": "^4.3.4", "tsutils": "^3.21.0" } }, "@typescript-eslint/types": { - "version": "5.30.7", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.7.tgz", - "integrity": "sha512-ocVkETUs82+U+HowkovV6uxf1AnVRKCmDRNUBUUo46/5SQv1owC/EBFkiu4MOHeZqhKz2ktZ3kvJJ1uFqQ8QPg==" + "version": "5.31.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.31.0.tgz", + "integrity": "sha512-/f/rMaEseux+I4wmR6mfpM2wvtNZb1p9hAV77hWfuKc3pmaANp5dLAZSiE3/8oXTYTt3uV9KW5yZKJsMievp6g==" }, "@typescript-eslint/typescript-estree": { - "version": "5.30.7", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.7.tgz", - "integrity": "sha512-tNslqXI1ZdmXXrHER83TJ8OTYl4epUzJC0aj2i4DMDT4iU+UqLT3EJeGQvJ17BMbm31x5scSwo3hPM0nqQ1AEA==", + "version": "5.31.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.31.0.tgz", + "integrity": "sha512-3S625TMcARX71wBc2qubHaoUwMEn+l9TCsaIzYI/ET31Xm2c9YQ+zhGgpydjorwQO9pLfR/6peTzS/0G3J/hDw==", "requires": { - "@typescript-eslint/types": "5.30.7", - "@typescript-eslint/visitor-keys": "5.30.7", + "@typescript-eslint/types": "5.31.0", + "@typescript-eslint/visitor-keys": "5.31.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -74067,24 +74571,24 @@ } }, "@typescript-eslint/utils": { - "version": "5.30.7", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.30.7.tgz", - "integrity": "sha512-Z3pHdbFw+ftZiGUnm1GZhkJgVqsDL5CYW2yj+TB2mfXDFOMqtbzQi2dNJIyPqPbx9mv2kUxS1gU+r2gKlKi1rQ==", + "version": "5.31.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.31.0.tgz", + "integrity": "sha512-kcVPdQS6VIpVTQ7QnGNKMFtdJdvnStkqS5LeALr4rcwx11G6OWb2HB17NMPnlRHvaZP38hL9iK8DdE9Fne7NYg==", "requires": { "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.30.7", - "@typescript-eslint/types": "5.30.7", - "@typescript-eslint/typescript-estree": "5.30.7", + "@typescript-eslint/scope-manager": "5.31.0", + "@typescript-eslint/types": "5.31.0", + "@typescript-eslint/typescript-estree": "5.31.0", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0" } }, "@typescript-eslint/visitor-keys": { - "version": "5.30.7", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.7.tgz", - "integrity": "sha512-KrRXf8nnjvcpxDFOKej4xkD7657+PClJs5cJVSG7NNoCNnjEdc46juNAQt7AyuWctuCgs6mVRc1xGctEqrjxWw==", + "version": "5.31.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.31.0.tgz", + "integrity": "sha512-ZK0jVxSjS4gnPirpVjXHz7mgdOsZUHzNYSfTw2yPa3agfbt9YfqaBiBZFSSxeBWnpWkzCxTfUpnzA3Vily/CSg==", "requires": { - "@typescript-eslint/types": "5.30.7", + "@typescript-eslint/types": "5.31.0", "eslint-visitor-keys": "^3.3.0" } }, @@ -74643,20 +75147,20 @@ } }, "webpack": { - "version": "5.73.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.73.0.tgz", - "integrity": "sha512-svjudQRPPa0YiOYa2lM/Gacw0r6PvxptHj4FuEKQ2kX05ZLkjbVc5MnPs6its5j7IZljnIqSVo/OsY2X0IpHGA==", + "version": "5.74.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz", + "integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==", "requires": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^0.0.51", "@webassemblyjs/ast": "1.11.1", "@webassemblyjs/wasm-edit": "1.11.1", "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.4.1", + "acorn": "^8.7.1", "acorn-import-assertions": "^1.7.6", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.9.3", + "enhanced-resolve": "^5.10.0", "es-module-lexer": "^0.9.0", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -74669,7 +75173,7 @@ "schema-utils": "^3.1.0", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.3.1", + "watchpack": "^2.4.0", "webpack-sources": "^3.2.3" } }, @@ -78288,9 +78792,9 @@ "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==" }, "ast-types": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.14.2.tgz", - "integrity": "sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==", + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", "requires": { "tslib": "^2.0.1" }, @@ -78417,9 +78921,9 @@ "integrity": "sha512-z4oo33lmnvvNRqfUe3YjDGGpqu/L2+wXBIhMtwq6oqZ+exOUAkQYM6zd2VWKF7AIlajOF8ZZuPFfryTG9iLC/w==" }, "aws-sdk": { - "version": "2.1181.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1181.0.tgz", - "integrity": "sha512-AAHSknRFAIjXBA/XNAL7gS79agr1LbS0oGimOJqJauGSJfWNaOpDc7z6OLNUQqGa5Joc3maD5QJcSKp1Pm/deQ==", + "version": "2.1182.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1182.0.tgz", + "integrity": "sha512-iemVvLTc2iy0rz3xTp8zc/kD27gIfDF/mk6bxY8/35xMulKCVANWUkAH8jWRKReHh5F/gX4bp33dnfG63ny1Ww==", "requires": { "buffer": "4.9.2", "events": "1.1.1", @@ -79652,6 +80156,13 @@ "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", "requires": { "file-uri-to-path": "1.0.0" + }, + "dependencies": { + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + } } }, "bintrees": { @@ -80013,14 +80524,14 @@ } }, "browserslist": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.2.tgz", - "integrity": "sha512-MonuOgAtUB46uP5CezYbRaYKBNt2LxP0yX+Pmj4LkcDFGkn9Cbpi83d9sCjwQDErXsIJSzY5oKGDbgOlF/LPAA==", + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.3.tgz", + "integrity": "sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==", "requires": { - "caniuse-lite": "^1.0.30001366", - "electron-to-chromium": "^1.4.188", + "caniuse-lite": "^1.0.30001370", + "electron-to-chromium": "^1.4.202", "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.4" + "update-browserslist-db": "^1.0.5" } }, "bs-logger": { @@ -80497,9 +81008,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001369", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001369.tgz", - "integrity": "sha512-OY1SBHaodJc4wflDIKnlkdqWzJZd1Ls/2zbVJHBSv3AT7vgOJ58yAhd2CN4d57l2kPJrgMb7P9+N1Mhy4tNSQA==" + "version": "1.0.30001370", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001370.tgz", + "integrity": "sha512-3PDmaP56wz/qz7G508xzjx8C+MC2qEm4SYhSEzC9IBROo+dGXFWRuaXkWti0A9tuI00g+toiriVqxtWMgl350g==" }, "capital-case": { "version": "1.0.4", @@ -80959,9 +81470,9 @@ } }, "cli-spinners": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", - "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==" + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz", + "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==" }, "cli-table3": { "version": "0.6.2", @@ -82558,6 +83069,11 @@ } } }, + "copy-to": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/copy-to/-/copy-to-2.0.1.tgz", + "integrity": "sha512-3DdaFaU/Zf1AnpLiFDeNCD4TOWe3Zl2RZaTzUvWiIk5ERzcCodOE20Vqq4fzCbNoHURFHT4/us/Lfq+S2zyY4w==" + }, "copy-webpack-plugin": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.1.2.tgz", @@ -82742,14 +83258,14 @@ } }, "core-js": { - "version": "3.23.5", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.23.5.tgz", - "integrity": "sha512-7Vh11tujtAZy82da4duVreQysIoO2EvVrur7y6IzZkH1IHPSekuDi8Vuw1+YKjkbfWLRD7Nc9ICQ/sIUDutcyg==" + "version": "3.24.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.24.0.tgz", + "integrity": "sha512-IeOyT8A6iK37Ep4kZDD423mpi6JfPRoPUdQwEWYiGolvn4o6j2diaRzNfDfpTdu3a5qMbrGUzKUpYpRY8jXCkQ==" }, "core-js-compat": { - "version": "3.23.5", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.23.5.tgz", - "integrity": "sha512-fHYozIFIxd+91IIbXJgWd/igXIc8Mf9is0fusswjnGIWVG96y2cwyUdlCkGOw6rMLHKAxg7xtCIVaHsyOUnJIg==", + "version": "3.24.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.24.0.tgz", + "integrity": "sha512-F+2E63X3ff/nj8uIrf8Rf24UDGIz7p838+xjEp+Bx3y8OWXj+VTPPZNCtdqovPaS9o7Tka5mCH01Zn5vOd6UQg==", "requires": { "browserslist": "^4.21.2", "semver": "7.0.0" @@ -82763,9 +83279,9 @@ } }, "core-js-pure": { - "version": "3.23.5", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.23.5.tgz", - "integrity": "sha512-8t78LdpKSuCq4pJYCYk8hl7XEkAX+BP16yRIwL3AanTksxuEf7CM83vRyctmiEL8NDZ3jpUcv56fk9/zG3aIuw==" + "version": "3.24.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.24.0.tgz", + "integrity": "sha512-uzMmW8cRh7uYw4JQtzqvGWRyC2T5+4zipQLQdi2FmiRqP83k3d6F3stv2iAlNhOs6cXN401FCD5TL0vvleuHgA==" }, "core-util-is": { "version": "1.0.3", @@ -83487,6 +84003,11 @@ "assert-plus": "^1.0.0" } }, + "data-uri-to-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz", + "integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==" + }, "data-urls": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", @@ -83923,6 +84444,25 @@ "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", "integrity": "sha512-2xaP6GiwVwOEbXCGoJ4ufgC76m8cj805jrghScewJC2ZDsb9U0b4BIrba+xt/Uytyd0HvQ6+WymSRTfnYj59GQ==" }, + "default-user-agent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/default-user-agent/-/default-user-agent-1.0.0.tgz", + "integrity": "sha512-bDF7bg6OSNcSwFWPu4zYKpVkJZQYVrAANMYB8bc9Szem1D0yKdm4sa/rOCs2aC9+2GMqQ7KnwtZRvDhmLF0dXw==", + "requires": { + "os-name": "~1.0.3" + }, + "dependencies": { + "os-name": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/os-name/-/os-name-1.0.3.tgz", + "integrity": "sha512-f5estLO2KN8vgtTRaILIgEGBoBrMnZ3JQ7W9TMZCnOIGwHe8TRGSpcagnWDo+Dfhd/z08k9Xe75hvciJJ8Qaew==", + "requires": { + "osx-release": "^1.0.0", + "win-release": "^1.0.0" + } + } + } + }, "defaults": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", @@ -83961,6 +84501,71 @@ "isobject": "^3.0.1" } }, + "degenerator": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-3.0.2.tgz", + "integrity": "sha512-c0mef3SNQo56t6urUU6tdQAs+ThoD0o9B9MJ8HEt7NQcGEILCRFqQb7ZbP9JAv+QF1Ky5plydhMR/IrqWDm+TQ==", + "requires": { + "ast-types": "^0.13.2", + "escodegen": "^1.8.1", + "esprima": "^4.0.0", + "vm2": "^3.9.8" + }, + "dependencies": { + "escodegen": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "requires": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==" + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "requires": { + "prelude-ls": "~1.1.2" + } + } + } + }, "del": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", @@ -84219,6 +84824,24 @@ "heap": ">= 0.2.0" } }, + "digest-header": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/digest-header/-/digest-header-0.0.1.tgz", + "integrity": "sha512-Qi0KOZgRnkQJuvMWbs1ZRRajEnbsMU8xlJI4rHIbPC+skHQ30heO5cIHpUFT4jAvAe+zPtdavLSAxASqoyZ3cg==", + "requires": { + "utility": "0.1.11" + }, + "dependencies": { + "utility": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/utility/-/utility-0.1.11.tgz", + "integrity": "sha512-epFsJ71+/yC7MKMX7CM9azP31QBIQhywkiBUj74i/T3Y2TXtEor26QBkat7lGamrrNTr5CBI1imd/8F0Bmqw4g==", + "requires": { + "address": ">=0.0.1" + } + } + } + }, "dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -84527,9 +85150,9 @@ } }, "electron-to-chromium": { - "version": "1.4.199", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.199.tgz", - "integrity": "sha512-WIGME0Cs7oob3mxsJwHbeWkH0tYkIE/sjkJ8ML2BYmuRcjhRl/q5kVDXG7W9LOOKwzPU5M0LBlXRq9rlSgnNlg==" + "version": "1.4.202", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.202.tgz", + "integrity": "sha512-JYsK2ex9lmQD27kj19fhXYxzFJ/phLAkLKHv49A5UY6kMRV2xED3qMMLg/voW/+0AR6wMiI+VxlmK9NDtdxlPA==" }, "element-ui": { "version": "2.15.9", @@ -84856,150 +85479,150 @@ } }, "esbuild": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.49.tgz", - "integrity": "sha512-/TlVHhOaq7Yz8N1OJrjqM3Auzo5wjvHFLk+T8pIue+fhnhIMpfAzsG6PLVMbFveVxqD2WOp3QHei+52IMUNmCw==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.50.tgz", + "integrity": "sha512-SbC3k35Ih2IC6trhbMYW7hYeGdjPKf9atTKwBUHqMCYFZZ9z8zhuvfnZihsnJypl74FjiAKjBRqFkBkAd0rS/w==", "requires": { - "esbuild-android-64": "0.14.49", - "esbuild-android-arm64": "0.14.49", - "esbuild-darwin-64": "0.14.49", - "esbuild-darwin-arm64": "0.14.49", - "esbuild-freebsd-64": "0.14.49", - "esbuild-freebsd-arm64": "0.14.49", - "esbuild-linux-32": "0.14.49", - "esbuild-linux-64": "0.14.49", - "esbuild-linux-arm": "0.14.49", - "esbuild-linux-arm64": "0.14.49", - "esbuild-linux-mips64le": "0.14.49", - "esbuild-linux-ppc64le": "0.14.49", - "esbuild-linux-riscv64": "0.14.49", - "esbuild-linux-s390x": "0.14.49", - "esbuild-netbsd-64": "0.14.49", - "esbuild-openbsd-64": "0.14.49", - "esbuild-sunos-64": "0.14.49", - "esbuild-windows-32": "0.14.49", - "esbuild-windows-64": "0.14.49", - "esbuild-windows-arm64": "0.14.49" + "esbuild-android-64": "0.14.50", + "esbuild-android-arm64": "0.14.50", + "esbuild-darwin-64": "0.14.50", + "esbuild-darwin-arm64": "0.14.50", + "esbuild-freebsd-64": "0.14.50", + "esbuild-freebsd-arm64": "0.14.50", + "esbuild-linux-32": "0.14.50", + "esbuild-linux-64": "0.14.50", + "esbuild-linux-arm": "0.14.50", + "esbuild-linux-arm64": "0.14.50", + "esbuild-linux-mips64le": "0.14.50", + "esbuild-linux-ppc64le": "0.14.50", + "esbuild-linux-riscv64": "0.14.50", + "esbuild-linux-s390x": "0.14.50", + "esbuild-netbsd-64": "0.14.50", + "esbuild-openbsd-64": "0.14.50", + "esbuild-sunos-64": "0.14.50", + "esbuild-windows-32": "0.14.50", + "esbuild-windows-64": "0.14.50", + "esbuild-windows-arm64": "0.14.50" } }, "esbuild-android-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.49.tgz", - "integrity": "sha512-vYsdOTD+yi+kquhBiFWl3tyxnj2qZJsl4tAqwhT90ktUdnyTizgle7TjNx6Ar1bN7wcwWqZ9QInfdk2WVagSww==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.50.tgz", + "integrity": "sha512-H7iUEm7gUJHzidsBlFPGF6FTExazcgXL/46xxLo6i6bMtPim6ZmXyTccS8yOMpy6HAC6dPZ/JCQqrkkin69n6Q==", "optional": true }, "esbuild-android-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.49.tgz", - "integrity": "sha512-g2HGr/hjOXCgSsvQZ1nK4nW/ei8JUx04Li74qub9qWrStlysaVmadRyTVuW32FGIpLQyc5sUjjZopj49eGGM2g==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.50.tgz", + "integrity": "sha512-NFaoqEwa+OYfoYVpQWDMdKII7wZZkAjtJFo1WdnBeCYlYikvUhTnf2aPwPu5qEAw/ie1NYK0yn3cafwP+kP+OQ==", "optional": true }, "esbuild-darwin-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.49.tgz", - "integrity": "sha512-3rvqnBCtX9ywso5fCHixt2GBCUsogNp9DjGmvbBohh31Ces34BVzFltMSxJpacNki96+WIcX5s/vum+ckXiLYg==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.50.tgz", + "integrity": "sha512-gDQsCvGnZiJv9cfdO48QqxkRV8oKAXgR2CGp7TdIpccwFdJMHf8hyIJhMW/05b/HJjET/26Us27Jx91BFfEVSA==", "optional": true }, "esbuild-darwin-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.49.tgz", - "integrity": "sha512-XMaqDxO846srnGlUSJnwbijV29MTKUATmOLyQSfswbK/2X5Uv28M9tTLUJcKKxzoo9lnkYPsx2o8EJcTYwCs/A==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.50.tgz", + "integrity": "sha512-36nNs5OjKIb/Q50Sgp8+rYW/PqirRiFN0NFc9hEvgPzNJxeJedktXwzfJSln4EcRFRh5Vz4IlqFRScp+aiBBzA==", "optional": true }, "esbuild-freebsd-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.49.tgz", - "integrity": "sha512-NJ5Q6AjV879mOHFri+5lZLTp5XsO2hQ+KSJYLbfY9DgCu8s6/Zl2prWXVANYTeCDLlrIlNNYw8y34xqyLDKOmQ==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.50.tgz", + "integrity": "sha512-/1pHHCUem8e/R86/uR+4v5diI2CtBdiWKiqGuPa9b/0x3Nwdh5AOH7lj+8823C6uX1e0ufwkSLkS+aFZiBCWxA==", "optional": true }, "esbuild-freebsd-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.49.tgz", - "integrity": "sha512-lFLtgXnAc3eXYqj5koPlBZvEbBSOSUbWO3gyY/0+4lBdRqELyz4bAuamHvmvHW5swJYL7kngzIZw6kdu25KGOA==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.50.tgz", + "integrity": "sha512-iKwUVMQztnPZe5pUYHdMkRc9aSpvoV1mkuHlCoPtxZA3V+Kg/ptpzkcSY+fKd0kuom+l6Rc93k0UPVkP7xoqrw==", "optional": true }, "esbuild-linux-32": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.49.tgz", - "integrity": "sha512-zTTH4gr2Kb8u4QcOpTDVn7Z8q7QEIvFl/+vHrI3cF6XOJS7iEI1FWslTo3uofB2+mn6sIJEQD9PrNZKoAAMDiA==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.50.tgz", + "integrity": "sha512-sWUwvf3uz7dFOpLzYuih+WQ7dRycrBWHCdoXJ4I4XdMxEHCECd8b7a9N9u7FzT6XR2gHPk9EzvchQUtiEMRwqw==", "optional": true }, "esbuild-linux-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.49.tgz", - "integrity": "sha512-hYmzRIDzFfLrB5c1SknkxzM8LdEUOusp6M2TnuQZJLRtxTgyPnZZVtyMeCLki0wKgYPXkFsAVhi8vzo2mBNeTg==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.50.tgz", + "integrity": "sha512-u0PQxPhaeI629t4Y3EEcQ0wmWG+tC/LpP2K7yDFvwuPq0jSQ8SIN+ARNYfRjGW15O2we3XJvklbGV0wRuUCPig==", "optional": true }, "esbuild-linux-arm": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.49.tgz", - "integrity": "sha512-iE3e+ZVv1Qz1Sy0gifIsarJMQ89Rpm9mtLSRtG3AH0FPgAzQ5Z5oU6vYzhc/3gSPi2UxdCOfRhw2onXuFw/0lg==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.50.tgz", + "integrity": "sha512-VALZq13bhmFJYFE/mLEb+9A0w5vo8z+YDVOWeaf9vOTrSC31RohRIwtxXBnVJ7YKLYfEMzcgFYf+OFln3Y0cWg==", "optional": true }, "esbuild-linux-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.49.tgz", - "integrity": "sha512-KLQ+WpeuY+7bxukxLz5VgkAAVQxUv67Ft4DmHIPIW+2w3ObBPQhqNoeQUHxopoW/aiOn3m99NSmSV+bs4BSsdA==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.50.tgz", + "integrity": "sha512-ZyfoNgsTftD7Rp5S7La5auomKdNeB3Ck+kSKXC4pp96VnHyYGjHHXWIlcbH8i+efRn9brszo1/Thl1qn8RqmhQ==", "optional": true }, "esbuild-linux-mips64le": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.49.tgz", - "integrity": "sha512-n+rGODfm8RSum5pFIqFQVQpYBw+AztL8s6o9kfx7tjfK0yIGF6tm5HlG6aRjodiiKkH2xAiIM+U4xtQVZYU4rA==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.50.tgz", + "integrity": "sha512-ygo31Vxn/WrmjKCHkBoutOlFG5yM9J2UhzHb0oWD9O61dGg+Hzjz9hjf5cmM7FBhAzdpOdEWHIrVOg2YAi6rTw==", "optional": true }, "esbuild-linux-ppc64le": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.49.tgz", - "integrity": "sha512-WP9zR4HX6iCBmMFH+XHHng2LmdoIeUmBpL4aL2TR8ruzXyT4dWrJ5BSbT8iNo6THN8lod6GOmYDLq/dgZLalGw==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.50.tgz", + "integrity": "sha512-xWCKU5UaiTUT6Wz/O7GKP9KWdfbsb7vhfgQzRfX4ahh5NZV4ozZ4+SdzYG8WxetsLy84UzLX3Pi++xpVn1OkFQ==", "optional": true }, "esbuild-linux-riscv64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.49.tgz", - "integrity": "sha512-h66ORBz+Dg+1KgLvzTVQEA1LX4XBd1SK0Fgbhhw4akpG/YkN8pS6OzYI/7SGENiN6ao5hETRDSkVcvU9NRtkMQ==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.50.tgz", + "integrity": "sha512-0+dsneSEihZTopoO9B6Z6K4j3uI7EdxBP7YSF5rTwUgCID+wHD3vM1gGT0m+pjCW+NOacU9kH/WE9N686FHAJg==", "optional": true }, "esbuild-linux-s390x": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.49.tgz", - "integrity": "sha512-DhrUoFVWD+XmKO1y7e4kNCqQHPs6twz6VV6Uezl/XHYGzM60rBewBF5jlZjG0nCk5W/Xy6y1xWeopkrhFFM0sQ==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.50.tgz", + "integrity": "sha512-tVjqcu8o0P9H4StwbIhL1sQYm5mWATlodKB6dpEZFkcyTI8kfIGWiWcrGmkNGH2i1kBUOsdlBafPxR3nzp3TDA==", "optional": true }, "esbuild-netbsd-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.49.tgz", - "integrity": "sha512-BXaUwFOfCy2T+hABtiPUIpWjAeWK9P8O41gR4Pg73hpzoygVGnj0nI3YK4SJhe52ELgtdgWP/ckIkbn2XaTxjQ==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.50.tgz", + "integrity": "sha512-0R/glfqAQ2q6MHDf7YJw/TulibugjizBxyPvZIcorH0Mb7vSimdHy0XF5uCba5CKt+r4wjax1mvO9lZ4jiAhEg==", "optional": true }, "esbuild-openbsd-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.49.tgz", - "integrity": "sha512-lP06UQeLDGmVPw9Rg437Btu6J9/BmyhdoefnQ4gDEJTtJvKtQaUcOQrhjTq455ouZN4EHFH1h28WOJVANK41kA==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.50.tgz", + "integrity": "sha512-7PAtmrR5mDOFubXIkuxYQ4bdNS6XCK8AIIHUiZxq1kL8cFIH5731jPcXQ4JNy/wbj1C9sZ8rzD8BIM80Tqk29w==", "optional": true }, "esbuild-sunos-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.49.tgz", - "integrity": "sha512-4c8Zowp+V3zIWje329BeLbGh6XI9c/rqARNaj5yPHdC61pHI9UNdDxT3rePPJeWcEZVKjkiAS6AP6kiITp7FSw==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.50.tgz", + "integrity": "sha512-gBxNY/wyptvD7PkHIYcq7se6SQEXcSC8Y7mE0FJB+CGgssEWf6vBPfTTZ2b6BWKnmaP6P6qb7s/KRIV5T2PxsQ==", "optional": true }, "esbuild-windows-32": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.49.tgz", - "integrity": "sha512-q7Rb+J9yHTeKr9QTPDYkqfkEj8/kcKz9lOabDuvEXpXuIcosWCJgo5Z7h/L4r7rbtTH4a8U2FGKb6s1eeOHmJA==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.50.tgz", + "integrity": "sha512-MOOe6J9cqe/iW1qbIVYSAqzJFh0p2LBLhVUIWdMVnNUNjvg2/4QNX4oT4IzgDeldU+Bym9/Tn6+DxvUHJXL5Zw==", "optional": true }, "esbuild-windows-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.49.tgz", - "integrity": "sha512-+Cme7Ongv0UIUTniPqfTX6mJ8Deo7VXw9xN0yJEN1lQMHDppTNmKwAM3oGbD/Vqff+07K2gN0WfNkMohmG+dVw==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.50.tgz", + "integrity": "sha512-r/qE5Ex3w1jjGv/JlpPoWB365ldkppUlnizhMxJgojp907ZF1PgLTuW207kgzZcSCXyquL9qJkMsY+MRtaZ5yQ==", "optional": true }, "esbuild-windows-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.49.tgz", - "integrity": "sha512-v+HYNAXzuANrCbbLFJ5nmO3m5y2PGZWLe3uloAkLt87aXiO2mZr3BTmacZdjwNkNEHuH3bNtN8cak+mzVjVPfA==", + "version": "0.14.50", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.50.tgz", + "integrity": "sha512-EMS4lQnsIe12ZyAinOINx7eq2mjpDdhGZZWDwPZE/yUTN9cnc2Ze/xUTYIAyaJqrqQda3LnDpADKpvLvol6ENQ==", "optional": true }, "escalade": { @@ -85500,9 +86123,9 @@ } }, "eslint-plugin-n8n-nodes-base": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-n8n-nodes-base/-/eslint-plugin-n8n-nodes-base-1.5.4.tgz", - "integrity": "sha512-w2anVulKpvNWrFVYtoPsGmMiJFFLiWJWiRVYKR29drRINEwII7YgyLeqjWkzYy/3y+u/l1hwr2Oh8RwDznoO4Q==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-n8n-nodes-base/-/eslint-plugin-n8n-nodes-base-1.5.5.tgz", + "integrity": "sha512-ZstoBrGzbsed/YssCWL4R8uRnH2T4qyox6cdyo2ICLhX3TSB9EIMIndo+D/+YWXEon6pX8r9MBgkIb+Q+LSXTg==", "requires": { "@typescript-eslint/utils": "^5.17.0", "camel-case": "^4.1.2", @@ -86362,9 +86985,9 @@ } }, "file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz", + "integrity": "sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg==" }, "filelist": { "version": "1.0.4", @@ -86990,6 +87613,23 @@ "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.6.tgz", "integrity": "sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ==" }, + "formstream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/formstream/-/formstream-1.1.1.tgz", + "integrity": "sha512-yHRxt3qLFnhsKAfhReM4w17jP+U1OlhUjnKPPtonwKbIJO7oBP0MvoxkRUwb8AU9n0MIkYy5X5dK6pQnbj+R2Q==", + "requires": { + "destroy": "^1.0.4", + "mime": "^2.5.2", + "pause-stream": "~0.0.11" + }, + "dependencies": { + "mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==" + } + } + }, "forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -87117,6 +87757,15 @@ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "optional": true }, + "ftp": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", + "integrity": "sha512-faFVML1aBx2UoDStmLwv2Wptt4vw5x03xxX172nhA5Y5HBshW5JweqQ2W4xL4dezQTG8inJsuYcpPHHU3X5OTQ==", + "requires": { + "readable-stream": "1.1.x", + "xregexp": "2.0.0" + } + }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -87441,6 +88090,49 @@ "resolved": "https://registry.npmjs.org/get-system-fonts/-/get-system-fonts-2.0.2.tgz", "integrity": "sha512-zzlgaYnHMIEgHRrfC7x0Qp0Ylhw/sHpM6MHXeVBTYIsvGf5GpbnClB+Q6rAPdn+0gd2oZZIo6Tj3EaWrt4VhDQ==" }, + "get-uri": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-3.0.2.tgz", + "integrity": "sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg==", + "requires": { + "@tootallnate/once": "1", + "data-uri-to-buffer": "3", + "debug": "4", + "file-uri-to-path": "2", + "fs-extra": "^8.1.0", + "ftp": "^0.3.10" + }, + "dependencies": { + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==" + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + } + } + }, "get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", @@ -89748,7 +90440,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", - "devOptional": true, "requires": { "ms": "^2.0.0" } @@ -95253,9 +95944,9 @@ } }, "libphonenumber-js": { - "version": "1.10.9", - "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.9.tgz", - "integrity": "sha512-BvPlectKyHuA8xVBU4PerKdI1t+l71F/GCh6CQhe4j5bTwibF6Jcle88kDcyvq4aW55CXxWZg7yIYhzmjgrjkQ==" + "version": "1.10.10", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.10.tgz", + "integrity": "sha512-JzYUapWcHkUe5n6OFqxJtHfCfuU0juqkqc9P+hrfzgmJODaREYLUgceiNAmIGx5j3Gjp7KVxi3koFo7OJFSTxg==" }, "libqp": { "version": "1.1.0", @@ -97202,6 +97893,11 @@ "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz", "integrity": "sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==" }, + "netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==" + }, "next-tick": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", @@ -98460,6 +99156,14 @@ "os-tmpdir": "^1.0.0" } }, + "osx-release": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/osx-release/-/osx-release-1.1.0.tgz", + "integrity": "sha512-ixCMMwnVxyHFQLQnINhmIpWqXIfS2YOXchwQrk+OFzmo6nDjQ0E4KXAyyUh0T0MZgV4bUhkRrAbVqlE4yLVq4A==", + "requires": { + "minimist": "^1.1.0" + } + }, "p-all": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/p-all/-/p-all-2.1.0.tgz", @@ -98624,6 +99328,66 @@ "p-reduce": "^1.0.0" } }, + "pac-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-5.0.0.tgz", + "integrity": "sha512-CcFG3ZtnxO8McDigozwE3AqAw15zDvGH+OjXO4kzf7IkEKkQ4gxQ+3sdF50WmhQ4P/bVusXcqNE2S3XrNURwzQ==", + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4", + "get-uri": "3", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "5", + "pac-resolver": "^5.0.0", + "raw-body": "^2.2.0", + "socks-proxy-agent": "5" + }, + "dependencies": { + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==" + }, + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + } + }, + "socks-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz", + "integrity": "sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==", + "requires": { + "agent-base": "^6.0.2", + "debug": "4", + "socks": "^2.3.3" + } + } + } + }, + "pac-resolver": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-5.0.1.tgz", + "integrity": "sha512-cy7u00ko2KVgBAjuhevqpPeHIkCIqPe1v24cydhWjmeuzaBfmUWFCZJ1iAh5TuVzVZoUzXIW7K8sMYOZ84uZ9Q==", + "requires": { + "degenerator": "^3.0.2", + "ip": "^1.1.5", + "netmask": "^2.0.2" + }, + "dependencies": { + "ip": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", + "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==" + } + } + }, "packet-reader": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", @@ -98818,14 +99582,14 @@ "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==" }, "parse-url": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-6.0.2.tgz", - "integrity": "sha512-uCSjOvD3T+6B/sPWhR+QowAZcU/o4bjPrVBQBGFxcDF6J6FraCGIaDBsdoQawiaaAVdHvtqBe3w3vKlfBKySOQ==", + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-6.0.5.tgz", + "integrity": "sha512-e35AeLTSIlkw/5GFq70IN7po8fmDUjpDPY1rIK+VubRfsUvBonjQ+PBZG+vWMACnQSmNlvl524IucoDmcioMxA==", "dev": true, "requires": { "is-ssh": "^1.3.0", "normalize-url": "^6.1.0", - "parse-path": "^4.0.4", + "parse-path": "^4.0.0", "protocols": "^1.4.0" }, "dependencies": { @@ -99065,6 +99829,14 @@ "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" }, + "pause-stream": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==", + "requires": { + "through": "~2.3" + } + }, "pbkdf2": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", @@ -100259,6 +101031,48 @@ "ipaddr.js": "1.9.1" } }, + "proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-5.0.0.tgz", + "integrity": "sha512-gkH7BkvLVkSfX9Dk27W6TyNOWWZWRilRfk1XxGNWOYJ2TuedAv1yFpCaU9QSBmBe716XOTNpYNOzhysyw8xn7g==", + "requires": { + "agent-base": "^6.0.0", + "debug": "4", + "http-proxy-agent": "^4.0.0", + "https-proxy-agent": "^5.0.0", + "lru-cache": "^5.1.1", + "pac-proxy-agent": "^5.0.0", + "proxy-from-env": "^1.0.0", + "socks-proxy-agent": "^5.0.0" + }, + "dependencies": { + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==" + }, + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + } + }, + "socks-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz", + "integrity": "sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==", + "requires": { + "agent-base": "^6.0.2", + "debug": "4", + "socks": "^2.3.3" + } + } + } + }, "proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -101210,6 +102024,14 @@ "tslib": "^2.0.1" }, "dependencies": { + "ast-types": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.14.2.tgz", + "integrity": "sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==", + "requires": { + "tslib": "^2.0.1" + } + }, "tslib": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", @@ -101797,15 +102619,6 @@ } } }, - "requestretry": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/requestretry/-/requestretry-7.1.0.tgz", - "integrity": "sha512-TqVDgp251BW4b8ddQ2ptaj/57Z3LZHLscAUT7v6qs70buqF2/IoOVjYbpjJ6HiW7j5+waqegGI8xKJ/+uzgDmw==", - "requires": { - "extend": "^3.0.2", - "lodash": "^4.17.15" - } - }, "require-at": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/require-at/-/require-at-1.0.6.tgz", @@ -101967,9 +102780,9 @@ "integrity": "sha512-fJhQQI5tLrQvYIYFpOnFinzv9dwmR7hRnUz1XqP3OJ1jIweTNOd6aTO4jwQSgcBSFUB+/KHJxuGneime+FdzOw==" }, "rollup": { - "version": "2.77.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.77.0.tgz", - "integrity": "sha512-vL8xjY4yOQEw79DvyXLijhnhh+R/O9zpF/LEgkCebZFtb6ELeN9H3/2T0r8+mp+fFTBHZ5qGpOpW2ela2zRt3g==", + "version": "2.77.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.77.2.tgz", + "integrity": "sha512-m/4YzYgLcpMQbxX3NmAqDvwLATZzxt8bIegO78FZLl+lAgKJBd1DRAOeEiZcKOIOPjxE6ewHWHNgGEalFXuz1g==", "requires": { "fsevents": "~2.3.2" } @@ -102759,8 +103572,7 @@ "smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "devOptional": true + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==" }, "snake-case": { "version": "3.0.4", @@ -102936,9 +103748,9 @@ } }, "snowflake-sdk": { - "version": "1.6.11", - "resolved": "https://registry.npmjs.org/snowflake-sdk/-/snowflake-sdk-1.6.11.tgz", - "integrity": "sha512-w4oCXjNQ1peAJjhnrwihr+epYw1pSxbe5/+PdxexYb2rzowyOn0RA5PFbir90q/dx0jzM2gvPiHDjnSBEZ1/zA==", + "version": "1.6.12", + "resolved": "https://registry.npmjs.org/snowflake-sdk/-/snowflake-sdk-1.6.12.tgz", + "integrity": "sha512-nkwtsWsZr4KrloLgpMpLgCnJIxfcuWlD4sqR53kn8BQRmhOi6cSBgnvZmoYcFvW2arVvfHh/Dc3vOQ/4OuRSLg==", "requires": { "@azure/storage-blob": "^12.5.0", "@techteamer/ocsp": "1.0.0", @@ -102964,12 +103776,11 @@ "moment-timezone": "^0.5.15", "open": "^7.3.1", "python-struct": "^1.1.3", - "request": "^2.88.2", - "requestretry": "^7.0.1", "simple-lru-cache": "^0.0.2", "string-similarity": "^4.0.4", "test-console": "^2.0.0", "tmp": "^0.2.1", + "urllib": "^2.38.0", "uuid": "^3.3.2", "winston": "^3.1.0" }, @@ -103047,7 +103858,6 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/socks/-/socks-2.3.3.tgz", "integrity": "sha512-o5t52PCNtVdiOvzMry7wU4aOqYWL0PeCXRWBEiJow4/i/wr+wpsJQ9awEu1EonLIqsfGd5qSgDdxEOvCdmBEpA==", - "dev": true, "requires": { "ip": "1.1.5", "smart-buffer": "^4.1.0" @@ -103056,8 +103866,7 @@ "ip": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha512-rBtCAQAJm8A110nbwn6YdveUnuZH3WrC36IwkRXxDnq53JvXA2NVQvB7IHyKomxK1MJ4VDNw3UtFDdXQ+AvLYA==", - "dev": true + "integrity": "sha512-rBtCAQAJm8A110nbwn6YdveUnuZH3WrC36IwkRXxDnq53JvXA2NVQvB7IHyKomxK1MJ4VDNw3UtFDdXQ+AvLYA==" } } }, @@ -106000,9 +106809,9 @@ "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" }, "uglify-js": { - "version": "3.16.2", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.16.2.tgz", - "integrity": "sha512-AaQNokTNgExWrkEYA24BTNMSjyqEXPSfhqoS0AxmHkCJ4U+Dyy5AvbGV/sqxuxficEfGGoX3zWw9R7QpLFfEsg==", + "version": "3.16.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.16.3.tgz", + "integrity": "sha512-uVbFqx9vvLhQg0iBaau9Z75AxWJ8tqM9AV890dIZCLApF4rTcyHwmAvLeEdYRs+BzYWu8Iw81F79ah0EfTXbaw==", "optional": true }, "uid-number": { @@ -106470,6 +107279,61 @@ "requires-port": "^1.0.0" } }, + "urllib": { + "version": "2.38.1", + "resolved": "https://registry.npmjs.org/urllib/-/urllib-2.38.1.tgz", + "integrity": "sha512-1tvjdL74oT9aV4X+SIjE1BXyes5PbfhHKhK4IlhoKhKqk4nD5/lXE90v10WZ02kELWIPI4w7ADneEQ4i7dPjiQ==", + "requires": { + "any-promise": "^1.3.0", + "content-type": "^1.0.2", + "debug": "^2.6.9", + "default-user-agent": "^1.0.0", + "digest-header": "^0.0.1", + "ee-first": "~1.1.1", + "formstream": "^1.1.0", + "humanize-ms": "^1.2.0", + "iconv-lite": "^0.4.15", + "ip": "^1.1.5", + "proxy-agent": "^5.0.0", + "pump": "^3.0.0", + "qs": "^6.4.0", + "statuses": "^1.3.1", + "utility": "^1.16.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ip": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", + "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==" + } + } + }, "use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", @@ -106541,6 +107405,18 @@ "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==" }, + "utility": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/utility/-/utility-1.17.0.tgz", + "integrity": "sha512-KdVkF9An/0239BJ4+dqOa7NPrPIOeQE9AGfx0XS16O9DBiHNHRJMoeU5nL6pRGAkgJOqdOu8R4gBRcXnAocJKw==", + "requires": { + "copy-to": "^2.0.1", + "escape-html": "^1.0.3", + "mkdirp": "^0.5.1", + "mz": "^2.7.0", + "unescape": "^1.0.1" + } + }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -106970,6 +107846,14 @@ "vue-inbrowser-compiler-utils": "^4.44.23" }, "dependencies": { + "ast-types": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.14.2.tgz", + "integrity": "sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==", + "requires": { + "tslib": "^2.0.1" + } + }, "hash-sum": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", @@ -106984,6 +107868,11 @@ "yallist": "^2.1.2" } }, + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, "yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", @@ -108875,6 +109764,21 @@ "string-width": "^4.0.0" } }, + "win-release": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/win-release/-/win-release-1.1.1.tgz", + "integrity": "sha512-iCRnKVvGxOQdsKhcQId2PXV1vV3J/sDPXKA4Oe9+Eti2nb2ESEsYHRYls/UjoUW3bIc5ZDO8dTH50A/5iVN+bw==", + "requires": { + "semver": "^5.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, "windows-release": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-3.3.3.tgz", From 6e28cae5f970c8ca4f02ab04143e8a5466700bb2 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Wed, 27 Jul 2022 15:38:53 +0000 Subject: [PATCH 060/609] =?UTF-8?q?:bookmark:=20Release=C2=A0n8n-workflow@?= =?UTF-8?q?0.110.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/workflow/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/workflow/package.json b/packages/workflow/package.json index 5aacc0523e2..a5e4ac800cc 100644 --- a/packages/workflow/package.json +++ b/packages/workflow/package.json @@ -1,6 +1,6 @@ { "name": "n8n-workflow", - "version": "0.109.0", + "version": "0.110.0", "description": "Workflow base code of n8n", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://n8n.io", From a80c28437265c41b896c8ed88126fe862935ddcf Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Wed, 27 Jul 2022 15:39:03 +0000 Subject: [PATCH 061/609] :arrow_up: Set n8n-workflow@0.110.0 on n8n-core --- packages/core/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/package.json b/packages/core/package.json index 6c0f17c296d..7ac71cbd383 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -51,7 +51,7 @@ "form-data": "^4.0.0", "lodash.get": "^4.4.2", "mime-types": "^2.1.27", - "n8n-workflow": "~0.109.0", + "n8n-workflow": "~0.110.0", "oauth-1.0a": "^2.2.6", "p-cancelable": "^2.0.0", "qs": "^6.10.1", From 385f5fb6c3e75ca4716242f0b78c75e68ad8520d Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Wed, 27 Jul 2022 15:39:03 +0000 Subject: [PATCH 062/609] =?UTF-8?q?:bookmark:=20Release=C2=A0n8n-core@0.12?= =?UTF-8?q?8.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/package.json b/packages/core/package.json index 7ac71cbd383..e5c28ef3136 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "n8n-core", - "version": "0.127.0", + "version": "0.128.0", "description": "Core functionality of n8n", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://n8n.io", From a7e926afe23d5bd642b8f285f381bc8feb0656f9 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Wed, 27 Jul 2022 15:39:11 +0000 Subject: [PATCH 063/609] :arrow_up: Set n8n-core@0.128.0 and n8n-workflow@0.110.0 on n8n-node-dev --- packages/node-dev/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/node-dev/package.json b/packages/node-dev/package.json index 94f43bbe8a2..866bce2e79c 100644 --- a/packages/node-dev/package.json +++ b/packages/node-dev/package.json @@ -60,8 +60,8 @@ "change-case": "^4.1.1", "copyfiles": "^2.1.1", "inquirer": "^7.0.1", - "n8n-core": "~0.127.0", - "n8n-workflow": "~0.109.0", + "n8n-core": "~0.128.0", + "n8n-workflow": "~0.110.0", "oauth-1.0a": "^2.2.6", "replace-in-file": "^6.0.0", "request": "^2.88.2", From 6c74fa9fae5b743602bda5049d8b439d204b0f90 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Wed, 27 Jul 2022 15:39:11 +0000 Subject: [PATCH 064/609] =?UTF-8?q?:bookmark:=20Release=C2=A0n8n-node-dev@?= =?UTF-8?q?0.67.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/node-dev/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/node-dev/package.json b/packages/node-dev/package.json index 866bce2e79c..c7783bbaa3f 100644 --- a/packages/node-dev/package.json +++ b/packages/node-dev/package.json @@ -1,6 +1,6 @@ { "name": "n8n-node-dev", - "version": "0.66.0", + "version": "0.67.0", "description": "CLI to simplify n8n credentials/node development", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://n8n.io", From ce14bf21255bd00ed6ed94cebcb77ad783274bbc Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Wed, 27 Jul 2022 15:39:18 +0000 Subject: [PATCH 065/609] :arrow_up: Set n8n-core@0.128.0 and n8n-workflow@0.110.0 on n8n-nodes-base --- packages/nodes-base/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index d057db22556..4d10a11eeb0 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -723,7 +723,7 @@ "eslint-plugin-n8n-nodes-base": "^1.5.4", "gulp": "^4.0.0", "jest": "^27.4.7", - "n8n-workflow": "~0.109.0", + "n8n-workflow": "~0.110.0", "ts-jest": "^27.1.3", "tslint": "^6.1.2", "typescript": "~4.6.0" @@ -764,7 +764,7 @@ "mqtt": "4.2.6", "mssql": "^8.1.2", "mysql2": "~2.3.0", - "n8n-core": "~0.127.0", + "n8n-core": "~0.128.0", "node-html-markdown": "^1.1.3", "node-ssh": "^12.0.0", "nodemailer": "^6.7.1", From 810836a318e107799c64ddffd74634574f85136b Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Wed, 27 Jul 2022 15:39:19 +0000 Subject: [PATCH 066/609] =?UTF-8?q?:bookmark:=20Release=C2=A0n8n-nodes-bas?= =?UTF-8?q?e@0.186.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/nodes-base/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index 4d10a11eeb0..b783b94920a 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -1,6 +1,6 @@ { "name": "n8n-nodes-base", - "version": "0.185.1", + "version": "0.186.0", "description": "Base nodes of n8n", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://n8n.io", From 75c3159353e7d1e58bbb08f3085a6e052c1da629 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Wed, 27 Jul 2022 15:40:02 +0000 Subject: [PATCH 067/609] =?UTF-8?q?:bookmark:=20Release=C2=A0n8n-design-sy?= =?UTF-8?q?stem@0.28.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/design-system/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/design-system/package.json b/packages/design-system/package.json index 5e995855ec4..5d5d3bb2482 100644 --- a/packages/design-system/package.json +++ b/packages/design-system/package.json @@ -1,6 +1,6 @@ { "name": "n8n-design-system", - "version": "0.27.0", + "version": "0.28.0", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://n8n.io", "author": { From c72e2da7a65c75afdbce1468d6df070905fb5c03 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Wed, 27 Jul 2022 15:40:10 +0000 Subject: [PATCH 068/609] :arrow_up: Set n8n-design-system@0.28.0 and n8n-workflow@0.110.0 on n8n-editor-ui --- packages/editor-ui/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/editor-ui/package.json b/packages/editor-ui/package.json index 06a944b9b9d..dfaa0399243 100644 --- a/packages/editor-ui/package.json +++ b/packages/editor-ui/package.json @@ -28,7 +28,7 @@ "@fortawesome/free-regular-svg-icons": "^6.1.1", "luxon": "^2.3.0", "monaco-editor": "^0.30.1", - "n8n-design-system": "~0.27.0", + "n8n-design-system": "~0.28.0", "timeago.js": "^4.0.2", "v-click-outside": "^3.1.2", "vue-fragment": "1.5.1", @@ -79,7 +79,7 @@ "lodash.debounce": "^4.0.8", "lodash.get": "^4.4.2", "lodash.set": "^4.3.2", - "n8n-workflow": "~0.109.0", + "n8n-workflow": "~0.110.0", "monaco-editor-webpack-plugin": "^5.0.0", "normalize-wheel": "^1.0.1", "prismjs": "^1.17.1", From 1d10f55356b0a9b3a3cd1dc524f15d55585f5bbe Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Wed, 27 Jul 2022 15:40:10 +0000 Subject: [PATCH 069/609] =?UTF-8?q?:bookmark:=20Release=C2=A0n8n-editor-ui?= =?UTF-8?q?@0.154.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/editor-ui/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor-ui/package.json b/packages/editor-ui/package.json index dfaa0399243..8870e4c45c8 100644 --- a/packages/editor-ui/package.json +++ b/packages/editor-ui/package.json @@ -1,6 +1,6 @@ { "name": "n8n-editor-ui", - "version": "0.153.1", + "version": "0.154.0", "description": "Workflow Editor UI for n8n", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://n8n.io", From 18e52129cb1c48c51e5825d865f436eb02c5db18 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Wed, 27 Jul 2022 15:41:37 +0000 Subject: [PATCH 070/609] :arrow_up: Set n8n-core@0.128.0, n8n-editor-ui@0.154.0, n8n-nodes-base@0.186.0 and n8n-workflow@0.110.0 on n8n --- packages/cli/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index a4a182c0c57..5e0bcd6f158 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -143,10 +143,10 @@ "lodash.split": "^4.4.2", "lodash.unset": "^4.5.2", "mysql2": "~2.3.0", - "n8n-core": "~0.127.0", - "n8n-editor-ui": "~0.153.1", - "n8n-nodes-base": "~0.185.1", - "n8n-workflow": "~0.109.0", + "n8n-core": "~0.128.0", + "n8n-editor-ui": "~0.154.0", + "n8n-nodes-base": "~0.186.0", + "n8n-workflow": "~0.110.0", "nodemailer": "^6.7.1", "oauth-1.0a": "^2.2.6", "open": "^7.0.0", From 8c7bc590ef1662f365a333f8d5960da090c5c421 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Wed, 27 Jul 2022 15:41:38 +0000 Subject: [PATCH 071/609] =?UTF-8?q?:bookmark:=20Release=C2=A0n8n@0.188.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/cli/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index 5e0bcd6f158..08f4ef6b7ae 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "n8n", - "version": "0.187.2", + "version": "0.188.0", "description": "n8n Workflow Automation Tool", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://n8n.io", From 92b2903ab758dc5f11d63e95998eb0f39fd9002a Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Wed, 27 Jul 2022 17:43:35 +0200 Subject: [PATCH 072/609] :bookmark: Update main package.json to 0.188.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ee00f0d225a..cdd878f763e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "n8n", - "version": "0.187.2", + "version": "0.188.0", "private": true, "homepage": "https://n8n.io", "scripts": { From 98aa2b7e4098f46ff04120b309c6467d3113cbb3 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Wed, 27 Jul 2022 17:44:30 +0200 Subject: [PATCH 073/609] :books: Update CHANGELOG.md with version 0.188.0 --- CHANGELOG.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1cd44fc2c65..4c96c597ea2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,29 @@ +# [0.188.0](https://github.com/n8n-io/n8n/compare/n8n@0.187.2...n8n@0.188.0) (2022-07-27) + + +### Bug Fixes + +* **AWS DynamoDB Node:** Fix expression attribute names ([#3763](https://github.com/n8n-io/n8n/issues/3763)) ([88cb265](https://github.com/n8n-io/n8n/commit/88cb26556c162aa1281dfa6a9fa8eca4cd071e9d)) +* **core:** Add windows support to import:credentials --separate ([#3589](https://github.com/n8n-io/n8n/issues/3589)) ([2fb590e](https://github.com/n8n-io/n8n/commit/2fb590e8440ac35567fdbf745b294d79feb8c5a9)) +* **editor:** Fix linking buttons color ([#3770](https://github.com/n8n-io/n8n/issues/3770)) ([deb510a](https://github.com/n8n-io/n8n/commit/deb510a8e0057280da43f3b3e72d8acca5829745)) +* **editor:** Fix pin data in executions when pinData is null. ([#3787](https://github.com/n8n-io/n8n/issues/3787)) ([30c0f21](https://github.com/n8n-io/n8n/commit/30c0f21b3f37280403848592877cb8658367b85e)) +* **editor:** Fix spaces bug ([#3774](https://github.com/n8n-io/n8n/issues/3774)) ([02549e3](https://github.com/n8n-io/n8n/commit/02549e3ba9233a6d9f75fc1f9ff138e2aff7f4b9)) +* **editor:** Fix sticky duplication and position bug ([#3755](https://github.com/n8n-io/n8n/issues/3755)) ([92614c8](https://github.com/n8n-io/n8n/commit/92614c81abfdbca51d4901b364467d3505870255)) +* **editor:** Restore pindata header colors ([#3758](https://github.com/n8n-io/n8n/issues/3758)) ([1a7318b](https://github.com/n8n-io/n8n/commit/1a7318b4cf6081e5ba743117cf90ef6920625aa0)) +* Fix node_type property in all events ([#3759](https://github.com/n8n-io/n8n/issues/3759)) ([1f1a63c](https://github.com/n8n-io/n8n/commit/1f1a63c39adc673259c951af3e5152c5edc34968)) +* **Fix Rocketchat Node:** Fix authentication issue ([#3778](https://github.com/n8n-io/n8n/issues/3778)) ([2710061](https://github.com/n8n-io/n8n/commit/271006152386511c19feb54e438fa60966dbf705)) +* **Mautic Node:** Fix authentication issue ([#3761](https://github.com/n8n-io/n8n/issues/3761)) ([fe58769](https://github.com/n8n-io/n8n/commit/fe58769b4830f388ad67ae1c32fcaa55aa0b848e)) + + +### Features + +* Improvements to pairedItem ([1348349](https://github.com/n8n-io/n8n/commit/13483497484e205975ef71091e3892f757f608e1)) +* **Item List Node:** Add operation for creating array from input items ([#3149](https://github.com/n8n-io/n8n/issues/3149)) ([553b14a](https://github.com/n8n-io/n8n/commit/553b14a13c7c9056447ef0b18c9427f26221b44d)) +* **Kafka Trigger Node:** Add additional options ([#3600](https://github.com/n8n-io/n8n/issues/3600)) ([3496a39](https://github.com/n8n-io/n8n/commit/3496a39788b654b46485955ba5cce5e5865babc7)) +* **Metabase Node:** Add Metabase Node ([#3033](https://github.com/n8n-io/n8n/issues/3033)) ([81b5828](https://github.com/n8n-io/n8n/commit/81b58285588f142c0b1cc148f0092c462eefdd73)) + + + ## [0.187.2](https://github.com/n8n-io/n8n/compare/n8n@0.187.1...n8n@0.187.2) (2022-07-21) From c2432e9f26432972115f649abc5c56ee097a1088 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Ovejero?= Date: Thu, 28 Jul 2022 11:14:48 +0200 Subject: [PATCH 074/609] :shirt: Adjust line endings for Prettier lintings (#3786) --- .eslintrc.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.eslintrc.js b/.eslintrc.js index 404f1cf155e..f4af9ed6d4b 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -84,7 +84,7 @@ module.exports = { // The following rule enables eslint-plugin-prettier // See: https://github.com/prettier/eslint-plugin-prettier#recommended-configuration - 'prettier/prettier': 'error', + 'prettier/prettier': ['error', { endOfLine: 'auto' }], // The following two rules must be disabled when using eslint-plugin-prettier: // See: https://github.com/prettier/eslint-plugin-prettier#arrow-body-style-and-prefer-arrow-callback-issue From ace49ef5354cc2001842b9ab0ba49d1d01c4bc47 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Fri, 29 Jul 2022 15:14:33 +0200 Subject: [PATCH 075/609] build: Use package-lock.json file with custom build --- docker/images/n8n-custom/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/docker/images/n8n-custom/Dockerfile b/docker/images/n8n-custom/Dockerfile index 7971197f91d..00c7026f909 100644 --- a/docker/images/n8n-custom/Dockerfile +++ b/docker/images/n8n-custom/Dockerfile @@ -12,6 +12,7 @@ WORKDIR /data COPY lerna.json . COPY package.json . +COPY package-lock.json . COPY packages/cli/ ./packages/cli/ COPY packages/core/ ./packages/core/ COPY packages/design-system/ ./packages/design-system/ From 43b9dc70cf2bdabe9987c413c5407931212ab0d8 Mon Sep 17 00:00:00 2001 From: Milorad Filipovic Date: Fri, 29 Jul 2022 15:19:15 +0200 Subject: [PATCH 076/609] =?UTF-8?q?=F0=9F=92=84=20Updating=20onboarding=20?= =?UTF-8?q?prompt=20label?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/editor-ui/src/plugins/i18n/locales/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor-ui/src/plugins/i18n/locales/en.json b/packages/editor-ui/src/plugins/i18n/locales/en.json index 1cbdca6fd98..4ad1674fa86 100644 --- a/packages/editor-ui/src/plugins/i18n/locales/en.json +++ b/packages/editor-ui/src/plugins/i18n/locales/en.json @@ -577,7 +577,7 @@ "onboardingCallSignupModal.signupButton.label": "Submit", "onboardingCallSignupModal.cancelButton.label": "Cancel", "onboardingCallSignupModal.infoText.emailError": "This doesn't seem to be a valid email address", - "onboardingCallSignupSucess.title": "Successfully signed up for an onboarding session", + "onboardingCallSignupSucess.title": "Check your email for the final step", "onboardingCallSignupSucess.message": "You should receive a message from us shortly", "onboardingCallSignupFailed.title": "Something went wrong", "onboardingCallSignupFailed.message": "Your request could not be sent", From b2c365d369257dd15d1e2e7fe7f02079479e865f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Ovejero?= Date: Fri, 29 Jul 2022 15:27:38 +0200 Subject: [PATCH 077/609] :arrow_up: Set eslint@8.0.0 on n8n-workflow (#3768) * :arrow_up: Upgrade `n8n-workflow` to ESLint 8 * :package: Update `package-lock.json` * :package: Re-update `package-lock.json` --- packages/workflow/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/workflow/package.json b/packages/workflow/package.json index a5e4ac800cc..eb95b620d05 100644 --- a/packages/workflow/package.json +++ b/packages/workflow/package.json @@ -39,7 +39,7 @@ "@types/xml2js": "^0.4.3", "@typescript-eslint/eslint-plugin": "^5.0.0", "@typescript-eslint/parser": "^5.0.0", - "eslint": "^7.32.0", + "eslint": "^8.0.0", "eslint-config-airbnb-typescript": "^12.3.1", "eslint-config-prettier": "^8.3.0", "eslint-plugin-import": "^2.23.4", From 3de062202d08947d40d9617a806e9c10a9eb291e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milorad=20FIlipovi=C4=87?= Date: Mon, 1 Aug 2022 22:35:45 +0200 Subject: [PATCH 078/609] refactor(editor): Implemented NodeIcon design system component (#3727) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ✨ Implemented `NodeIcon` design system component * ✨ Updated editor to use N8nNodeIcon component, removed HoverableNodeIcon * ➕ Adding design system types import to editor-ui * ✔️ Fixing linting errors * 👌 Updating `NodeIcon` component based on review feedback * 👌 Minor changes to `NodeIcon` component * 👌 Removing unnecessary `Vue.use statement * 🐛 Fixing unknown node icon bug and adding click listener to node icon component * 💄 Removing unnecessary pointer cursor from the `NodeIcon` component * 💄 Adding pointer cursor to node icons in the template details * 💄 Updating node icon size in collections page --- .../N8nNodeIcon/NodeIcon.stories.ts | 40 ++++ .../src/components/N8nNodeIcon/NodeIcon.vue | 135 ++++++++++++++ .../src/components/N8nNodeIcon/index.ts | 3 + .../design-system/src/components/index.ts | 2 + .../editor-ui/src/components/NodeIcon.vue | 171 +++++++----------- .../editor-ui/src/components/NodeList.vue | 19 +- .../src/components/TemplateDetails.vue | 14 +- packages/editor-ui/src/plugins/components.ts | 2 + packages/editor-ui/src/shims-vue.d.ts | 1 + 9 files changed, 259 insertions(+), 128 deletions(-) create mode 100644 packages/design-system/src/components/N8nNodeIcon/NodeIcon.stories.ts create mode 100644 packages/design-system/src/components/N8nNodeIcon/NodeIcon.vue create mode 100644 packages/design-system/src/components/N8nNodeIcon/index.ts diff --git a/packages/design-system/src/components/N8nNodeIcon/NodeIcon.stories.ts b/packages/design-system/src/components/N8nNodeIcon/NodeIcon.stories.ts new file mode 100644 index 00000000000..5a6ab12ba24 --- /dev/null +++ b/packages/design-system/src/components/N8nNodeIcon/NodeIcon.stories.ts @@ -0,0 +1,40 @@ +/* tslint:disable:variable-name */ +import N8nNodeIcon from "./NodeIcon.vue"; +import { StoryFn } from '@storybook/vue'; + +export default { + title: 'Atoms/NodeIcon', + component: N8nNodeIcon, +}; + +const DefaultTemplate: StoryFn = (args, { argTypes }) => ({ + props: Object.keys(argTypes), + components: { + N8nNodeIcon, + }, + template: '', +}); + +export const FileIcon = DefaultTemplate.bind({}); +FileIcon.args = { + type: 'file', + src: 'https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/cartman.svg', + size: 200, +}; + +export const FontIcon = DefaultTemplate.bind({}); +FontIcon.args = { + type: 'icon', + name: 'cogs', + size: 200, +}; + +export const Hoverable = DefaultTemplate.bind({}); +Hoverable.args = { + type: 'icon', + name: 'heart', + color: 'red', + size: 200, + nodeTypeName: 'We ❤️ n8n', + showTooltip: true, +}; diff --git a/packages/design-system/src/components/N8nNodeIcon/NodeIcon.vue b/packages/design-system/src/components/N8nNodeIcon/NodeIcon.vue new file mode 100644 index 00000000000..dcee0d6338c --- /dev/null +++ b/packages/design-system/src/components/N8nNodeIcon/NodeIcon.vue @@ -0,0 +1,135 @@ + + + + + diff --git a/packages/design-system/src/components/N8nNodeIcon/index.ts b/packages/design-system/src/components/N8nNodeIcon/index.ts new file mode 100644 index 00000000000..c251d7fed1c --- /dev/null +++ b/packages/design-system/src/components/N8nNodeIcon/index.ts @@ -0,0 +1,3 @@ +import N8nNodeIcon from './NodeIcon.vue'; + +export default N8nNodeIcon; diff --git a/packages/design-system/src/components/index.ts b/packages/design-system/src/components/index.ts index c6deea05fc4..a0d2487308c 100644 --- a/packages/design-system/src/components/index.ts +++ b/packages/design-system/src/components/index.ts @@ -57,6 +57,7 @@ import N8nLoading from './N8nLoading'; import N8nMarkdown from './N8nMarkdown'; import N8nMenu from './N8nMenu'; import N8nMenuItem from './N8nMenuItem'; +import N8nNodeIcon from './N8nNodeIcon'; import N8nNotice from './N8nNotice'; import N8nLink from './N8nLink'; import N8nOption from './N8nOption'; @@ -103,6 +104,7 @@ export { N8nMenu, N8nMenuItem, N8nNotice, + N8nNodeIcon, N8nOption, N8nPulse, N8nRadioButtons, diff --git a/packages/editor-ui/src/components/NodeIcon.vue b/packages/editor-ui/src/components/NodeIcon.vue index 6ff2e910a0d..6d397432d36 100644 --- a/packages/editor-ui/src/components/NodeIcon.vue +++ b/packages/editor-ui/src/components/NodeIcon.vue @@ -1,34 +1,37 @@ diff --git a/packages/editor-ui/src/components/NodeList.vue b/packages/editor-ui/src/components/NodeList.vue index bf9f04cea17..70deedc5607 100644 --- a/packages/editor-ui/src/components/NodeList.vue +++ b/packages/editor-ui/src/components/NodeList.vue @@ -1,7 +1,11 @@ @@ -79,4 +91,10 @@ export default { color: var(--color-text-base); margin-bottom: var(--spacing-xl); } + +.callout { + width: 100%; + text-align: left; +} + diff --git a/packages/design-system/src/components/N8nCallout/Callout.stories.ts b/packages/design-system/src/components/N8nCallout/Callout.stories.ts index 04bb81626db..ea7f49b43c3 100644 --- a/packages/design-system/src/components/N8nCallout/Callout.stories.ts +++ b/packages/design-system/src/components/N8nCallout/Callout.stories.ts @@ -1,6 +1,9 @@ import N8nCallout from './Callout.vue'; +import N8nLink from '../N8nLink'; +import N8nText from '../N8nText'; import { StoryFn } from '@storybook/vue'; + export default { title: 'Atoms/Callout', component: N8nCallout, @@ -8,7 +11,7 @@ export default { theme: { control: { type: 'select', - options: ['info', 'success', 'warning', 'danger', 'custom'], + options: ['info', 'secondary', 'success', 'warning', 'danger', 'custom'], }, }, message: { @@ -22,19 +25,84 @@ export default { }, }, }, + parameters: { + design: { + type: 'figma', + url: 'https://www.figma.com/file/tPpJvbrnHbP8C496cYuwyW/Node-pinning?node-id=15%3A5777', + }, + }, }; const template : StoryFn = (args, { argTypes }) => ({ props: Object.keys(argTypes), components: { + N8nLink, + N8nText, N8nCallout, }, - template: ``, + template: ` + + ${args.default} + + + + `, }); -export const callout = template.bind({}); -callout.args = { +export const defaultCallout = template.bind({}); +defaultCallout.args = { + theme: 'success', + default: ` + + This is a default callout. + + `, +}; + +export const customCallout = template.bind({}); +customCallout.args = { theme: 'custom', icon: 'code-branch', - message: 'This is a callout. Read more.', + default: ` + + This is a custom callout. + + `, + actions: ` + + Do something! + + `, +}; + + +export const secondaryCallout = template.bind({}); +secondaryCallout.args = { + theme: 'secondary', + icon: 'thumbtack', + default: ` + + This data is pinned. + + `, + actions: ` + + Unpin + + `, + trailingContent: ` + + Learn more + + `, }; diff --git a/packages/design-system/src/components/N8nCallout/Callout.vue b/packages/design-system/src/components/N8nCallout/Callout.vue index f64f8b3a9f7..979fb4f63df 100644 --- a/packages/design-system/src/components/N8nCallout/Callout.vue +++ b/packages/design-system/src/components/N8nCallout/Callout.vue @@ -1,11 +1,18 @@ @@ -14,37 +21,30 @@ import Vue from 'vue'; import N8nIcon from '../N8nIcon'; import N8nText from '../N8nText'; +const CALLOUT_DEFAULT_ICONS = { + info: 'info-circle', + success: 'check-circle', + warning: 'exclamation-triangle', + danger: 'times-circle', +}; + export default Vue.extend({ name: 'n8n-callout', components: { N8nIcon, - N8nText + N8nText, }, props: { theme: { type: String, required: true, validator: (value: string): boolean => - ['info', 'success', 'warning', 'danger', 'custom'].includes(value), - }, - message: { - type: String, - required: true + ['info', 'success', 'secondary', 'warning', 'danger', 'custom'].includes(value), }, icon: { type: String, default: 'info-circle' - } - }, - data() { - return { - defaultIcons: { - 'info': 'info-circle', - 'success': 'check-circle', - 'warning': 'exclamation-triangle', - 'danger': 'times-circle', - } - } + }, }, computed: { classes(): string[] { @@ -54,50 +54,65 @@ export default Vue.extend({ ]; }, getIcon(): string { - if(this.theme === 'custom') { - return this.icon; + if (Object.keys(CALLOUT_DEFAULT_ICONS).includes(this.theme)) { + return CALLOUT_DEFAULT_ICONS[this.theme]; } - return this.defaultIcons[this.theme]; + + return this.icon; }, } }); diff --git a/packages/design-system/src/components/N8nCallout/N8nCallout.stories.ts b/packages/design-system/src/components/N8nCallout/N8nCallout.stories.ts deleted file mode 100644 index 0c7a315e197..00000000000 --- a/packages/design-system/src/components/N8nCallout/N8nCallout.stories.ts +++ /dev/null @@ -1,107 +0,0 @@ -import N8nCallout from './Callout.vue'; -import { StoryFn } from '@storybook/vue'; -import N8nLink from '../N8nLink'; -import N8nText from '../N8nText'; - -export default { - title: 'Atoms/Callout', - component: N8nCallout, - argTypes: { - theme: { - control: { - type: 'select', - options: ['info', 'secondary', 'success', 'warning', 'danger', 'custom'], - }, - }, - message: { - control: { - type: 'text', - }, - }, - icon: { - control: { - type: 'text', - }, - }, - }, - parameters: { - design: { - type: 'figma', - url: 'https://www.figma.com/file/tPpJvbrnHbP8C496cYuwyW/Node-pinning?node-id=15%3A5777', - }, - }, -}; - -const template: StoryFn = (args, { argTypes }) => ({ - props: Object.keys(argTypes), - components: { - N8nLink, - N8nText, - N8nCallout, - }, - template: ` - - ${args.default} - - - - `, -}); - -export const customCallout = template.bind({}); -customCallout.args = { - theme: 'custom', - icon: 'code-branch', - default: ` - - This is a callout. - - `, - actions: ` - - Do something! - - `, -}; - -export const secondaryCallout = template.bind({}); -secondaryCallout.args = { - theme: 'secondary', - icon: 'thumbtack', - default: ` - - This data is pinned. - - `, - actions: ` - - Unpin - - `, - trailingContent: ` - - Learn more - - `, -}; diff --git a/packages/design-system/src/components/N8nCallout/__tests__/Callout.spec.ts b/packages/design-system/src/components/N8nCallout/__tests__/Callout.spec.ts index 1740989427c..799812eebfd 100644 --- a/packages/design-system/src/components/N8nCallout/__tests__/Callout.spec.ts +++ b/packages/design-system/src/components/N8nCallout/__tests__/Callout.spec.ts @@ -2,106 +2,94 @@ import { render } from '@testing-library/vue'; import N8nCallout from '../Callout.vue'; describe('components', () => { - describe('N8NCallout', () => { - describe('props', () => { - it('should render info theme correctly', () => { - const wrapper = render(N8nCallout, { - props: { - theme: 'info', - message: 'This is an info callout.', - }, - stubs: [ - 'n8n-icon', - 'n8n-text', - ], - }); - expect(wrapper.html()).toMatchSnapshot(); - }); - it('should render success theme correctly', () => { - const wrapper = render(N8nCallout, { - props: { - theme: 'success', - message: 'This is an success callout.', - }, - stubs: [ - 'n8n-icon', - 'n8n-text', - ], - }); - expect(wrapper.html()).toMatchSnapshot(); - }); - it('should render warning theme correctly', () => { - const wrapper = render(N8nCallout, { - props: { - theme: 'warning', - message: 'This is an warning callout.', - }, - stubs: [ - 'n8n-icon', - 'n8n-text', - ], - }); - expect(wrapper.html()).toMatchSnapshot(); - }); - it('should render danger theme correctly', () => { - const wrapper = render(N8nCallout, { - props: { - theme: 'danger', - message: 'This is an danger callout.', - }, - stubs: [ - 'n8n-icon', - 'n8n-text', - ], - }); - expect(wrapper.html()).toMatchSnapshot(); - }); - it('should render custom theme correctly', () => { - const wrapper = render(N8nCallout, { - props: { - theme: 'custom', - message: 'This is an custom callout.', - icon: 'code', - }, - stubs: [ - 'n8n-icon', - 'n8n-text', - ], - }); - expect(wrapper.html()).toMatchSnapshot(); + describe('N8nCallout', () => { + it('should render info theme correctly', () => { + const wrapper = render(N8nCallout, { + props: { + theme: 'info', + }, + stubs: [ 'n8n-icon', 'n8n-text' ], + slots: { + default: 'This is an info callout.', + }, }); + expect(wrapper.html()).toMatchSnapshot(); }); - describe('content', () => { - it('should render custom HTML content correctly', () => { - const wrapper = render(N8nCallout, { - props: { - theme: 'custom', - message: 'This is an HTML callout. Read more', - icon: 'code', - }, - stubs: [ - 'n8n-icon', - 'n8n-text', - ], - }); - expect(wrapper.html()).toMatchSnapshot(); + it('should render success theme correctly', () => { + const wrapper = render(N8nCallout, { + props: { + theme: 'success', + }, + stubs: [ 'n8n-icon', 'n8n-text' ], + slots: { + default: 'This is a success callout.', + }, }); - it('should pass props to text component correctly', () => { - const wrapper = render(N8nCallout, { - props: { - theme: 'warning', - message: 'This is a callout.', - bold: true, - align: 'center', - tag: 'p', - }, - stubs: [ - 'n8n-icon', - 'n8n-text', - ], - }); - expect(wrapper.html()).toMatchSnapshot(); + expect(wrapper.html()).toMatchSnapshot(); + }); + it('should render warning theme correctly', () => { + const wrapper = render(N8nCallout, { + props: { + theme: 'warning', + }, + stubs: [ 'n8n-icon', 'n8n-text' ], + slots: { + default: 'This is a warning callout.', + }, }); + expect(wrapper.html()).toMatchSnapshot(); + }); + it('should render danger theme correctly', () => { + const wrapper = render(N8nCallout, { + props: { + theme: 'danger', + }, + stubs: [ 'n8n-icon', 'n8n-text' ], + slots: { + default: 'This is a danger callout.', + }, + }); + expect(wrapper.html()).toMatchSnapshot(); + }); + it('should render secondary theme correctly', () => { + const wrapper = render(N8nCallout, { + props: { + theme: 'secondary', + }, + stubs: [ 'n8n-icon', 'n8n-text' ], + slots: { + default: 'This is a secondary callout.', + }, + }); + expect(wrapper.html()).toMatchSnapshot(); + }); + it('should render custom theme correctly', () => { + const wrapper = render(N8nCallout, { + props: { + theme: 'custom', + icon: 'code-branch', + }, + stubs: [ 'n8n-icon', 'n8n-text' ], + slots: { + default: 'This is a secondary callout.', + }, + }); + expect(wrapper.html()).toMatchSnapshot(); + }); + it('should render additional slots correctly', () => { + const wrapper = render(N8nCallout, { + props: { + theme: 'custom', + icon: 'code-branch', + }, + stubs: [ 'n8n-icon', 'n8n-text', 'n8n-link' ], + slots: { + default: 'This is a secondary callout.', + actions: 'Do something!', + trailingContent: 'Learn more', + }, + }); + expect(wrapper.html()).toMatchSnapshot(); }); }); }); diff --git a/packages/design-system/src/components/N8nCallout/__tests__/__snapshots__/Callout.spec.ts.snap b/packages/design-system/src/components/N8nCallout/__tests__/__snapshots__/Callout.spec.ts.snap index db3b1dfacb7..b71ea8250c6 100644 --- a/packages/design-system/src/components/N8nCallout/__tests__/__snapshots__/Callout.spec.ts.snap +++ b/packages/design-system/src/components/N8nCallout/__tests__/__snapshots__/Callout.spec.ts.snap @@ -1,78 +1,79 @@ // Vitest Snapshot v1 -exports[`components > N8NCallout > content > should pass props to text component correctly 1`] = ` -"
-
- +exports[`components > N8nCallout > should render additional slots correctly 1`] = ` +"
+
+
+ +
+ This is a secondary callout.  Do something!
-
- This is a callout. + Learn more +
" +`; + +exports[`components > N8nCallout > should render custom theme correctly 1`] = ` +"
+
+
+ +
+ This is a secondary callout. 
" `; -exports[`components > N8NCallout > content > should render custom HTML content correctly 1`] = ` -"
-
- -
-
- This is an HTML callout. Read more +exports[`components > N8nCallout > should render danger theme correctly 1`] = ` +"
+
+
+ +
+ This is a danger callout. 
" `; -exports[`components > N8NCallout > props > should render custom theme correctly 1`] = ` -"
-
- -
-
- This is an custom callout. +exports[`components > N8nCallout > should render info theme correctly 1`] = ` +"
+
+
+ +
+ This is an info callout. 
" `; -exports[`components > N8NCallout > props > should render danger theme correctly 1`] = ` -"
-
- -
-
- This is an danger callout. +exports[`components > N8nCallout > should render secondary theme correctly 1`] = ` +"
+
+
+ +
+ This is a secondary callout. 
" `; -exports[`components > N8NCallout > props > should render info theme correctly 1`] = ` -"
-
- -
-
- This is an info callout. +exports[`components > N8nCallout > should render success theme correctly 1`] = ` +"
+
+
+ +
+ This is a success callout. 
" `; -exports[`components > N8NCallout > props > should render success theme correctly 1`] = ` -"
-
- -
-
- This is an success callout. -
-
" -`; - -exports[`components > N8NCallout > props > should render warning theme correctly 1`] = ` -"
-
- -
-
- This is an warning callout. +exports[`components > N8nCallout > should render warning theme correctly 1`] = ` +"
+
+
+ +
+ This is a warning callout. 
" `; diff --git a/packages/design-system/src/components/N8nPanelCallout/PanelCallout.stories.js b/packages/design-system/src/components/N8nPanelCallout/PanelCallout.stories.js deleted file mode 100644 index 5b500e10ab8..00000000000 --- a/packages/design-system/src/components/N8nPanelCallout/PanelCallout.stories.js +++ /dev/null @@ -1,107 +0,0 @@ -import N8nPanelCallout from './PanelCallout.vue'; -import { StoryFn } from '@storybook/vue'; -import N8nLink from '../N8nLink'; -import N8nText from '../N8nText'; - -export default { - title: 'Atoms/Callout', - component: N8nPanelCallout, - argTypes: { - theme: { - control: { - type: 'select', - options: ['info', 'secondary', 'success', 'warning', 'danger', 'custom'], - }, - }, - message: { - control: { - type: 'text', - }, - }, - icon: { - control: { - type: 'text', - }, - }, - }, - parameters: { - design: { - type: 'figma', - url: 'https://www.figma.com/file/tPpJvbrnHbP8C496cYuwyW/Node-pinning?node-id=15%3A5777', - }, - }, -}; - -const template = (args, { argTypes }) => ({ - props: Object.keys(argTypes), - components: { - N8nLink, - N8nText, - N8nPanelCallout, - }, - template: ` - - ${args.default} - - - - `, -}); - -export const customCallout = template.bind({}); -customCallout.args = { - theme: 'custom', - icon: 'code-branch', - default: ` - - This is a callout. - - `, - actions: ` - - Do something! - - `, -}; - -export const secondaryCallout = template.bind({}); -secondaryCallout.args = { - theme: 'secondary', - icon: 'thumbtack', - default: ` - - This data is pinned. - - `, - actions: ` - - Unpin - - `, - trailingContent: ` - - Learn more - - `, -}; diff --git a/packages/design-system/src/components/N8nPanelCallout/PanelCallout.vue b/packages/design-system/src/components/N8nPanelCallout/PanelCallout.vue deleted file mode 100644 index c55cdbc508e..00000000000 --- a/packages/design-system/src/components/N8nPanelCallout/PanelCallout.vue +++ /dev/null @@ -1,115 +0,0 @@ - - - - - diff --git a/packages/design-system/src/components/N8nPanelCallout/index.ts b/packages/design-system/src/components/N8nPanelCallout/index.ts deleted file mode 100644 index 8ada19c2f39..00000000000 --- a/packages/design-system/src/components/N8nPanelCallout/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import N8nPanelCallout from './PanelCallout.vue'; - -export default N8nPanelCallout; diff --git a/packages/design-system/src/components/index.ts b/packages/design-system/src/components/index.ts index a0d2487308c..57c4356ef15 100644 --- a/packages/design-system/src/components/index.ts +++ b/packages/design-system/src/components/index.ts @@ -41,7 +41,6 @@ import N8nBadge from './N8nBadge'; import N8nButton from './N8nButton'; import { N8nElButton } from './N8nButton/overrides'; import N8nCallout from './N8nCallout'; -import N8nPanelCallout from './N8nPanelCallout'; import N8nCard from './N8nCard'; import N8nFormBox from './N8nFormBox'; import N8nFormInput from './N8nFormInput'; @@ -86,7 +85,6 @@ export { N8nButton, N8nElButton, N8nCallout, - N8nPanelCallout, N8nCard, N8nHeading, N8nFormBox, diff --git a/packages/editor-ui/src/components/RunData.vue b/packages/editor-ui/src/components/RunData.vue index 99d57758fee..0c682876d5c 100644 --- a/packages/editor-ui/src/components/RunData.vue +++ b/packages/editor-ui/src/components/RunData.vue @@ -1,6 +1,6 @@ - + diff --git a/packages/editor-ui/src/plugins/components.ts b/packages/editor-ui/src/plugins/components.ts index 354857d0c0a..07c750cc6cd 100644 --- a/packages/editor-ui/src/plugins/components.ts +++ b/packages/editor-ui/src/plugins/components.ts @@ -51,7 +51,6 @@ import { N8nButton, N8nElButton, N8nCallout, - N8nPanelCallout, N8nCard, N8nIcon, N8nIconButton, @@ -94,7 +93,6 @@ Vue.use(N8nAvatar); Vue.component('n8n-button', N8nButton); Vue.component('el-button', N8nElButton); Vue.component('n8n-callout', N8nCallout); -Vue.component('n8n-panel-callout', N8nPanelCallout); Vue.component('n8n-card', N8nCard); Vue.component('n8n-form-box', N8nFormBox); Vue.component('n8n-form-inputs', N8nFormInputs); diff --git a/packages/editor-ui/src/views/SettingsCommunityNodesView.vue b/packages/editor-ui/src/views/SettingsCommunityNodesView.vue index 9e09585387e..0b5cc79c8a3 100644 --- a/packages/editor-ui/src/views/SettingsCommunityNodesView.vue +++ b/packages/editor-ui/src/views/SettingsCommunityNodesView.vue @@ -10,15 +10,15 @@ @click="openInstallModal" />
- +
+ +
Date: Tue, 2 Aug 2022 10:40:57 +0200 Subject: [PATCH 083/609] refactor(core): Improve community node repo code (#3767) * :blue_book: Tighten `NodeRequest` * :blue: Add `AuthAgent` type * :zap: Add constants * :blue_book: Namespace npm types * :test_tube: Set up `createAuthAgent` * :test_tube: Refactor helpers tests * :test_tube: Refactor endpoints tests * :zap: Refactor CNR helpers * :zap: Return promises in `packageModel` * :zap: Refactor endpoints * :pencil2: Restore naming * :heavy_plus_sign: Expose dependency `jest-mock` * :package: Update `package-lock.json` * :package: Update `package-lock.json` * :shirt: Fix lint * :truck: Rename namespace * :fire: Remove outdated comment * :bug: Fix `Promise` comparison * :rewind: Undo `ResponseHelper` change * :pencil2: Document `ResponseError` * :art: Fix formatting --- package-lock.json | 156 ++++- packages/cli/package.json | 3 +- packages/cli/src/CommunityNodes/helpers.ts | 185 +++--- .../cli/src/CommunityNodes/packageModel.ts | 23 +- packages/cli/src/Interfaces.ts | 44 +- packages/cli/src/ResponseHelper.ts | 2 + packages/cli/src/api/nodes.api.ts | 376 ++++++------ packages/cli/src/constants.ts | 3 + packages/cli/src/requests.d.ts | 12 +- .../cli/test/integration/nodes.api.test.ts | 506 ++++++++-------- .../cli/test/integration/shared/types.d.ts | 9 +- packages/cli/test/integration/shared/utils.ts | 23 +- .../test/unit/CommunityNodeHelpers.test.ts | 567 +++++++++--------- 13 files changed, 1042 insertions(+), 867 deletions(-) diff --git a/package-lock.json b/package-lock.json index f9eef4ce72c..5edf2784abd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -171,6 +171,7 @@ "iso-639-1": "^2.1.3", "jest": "^27.4.7", "jest-environment-jsdom": "^27.5.1", + "jest-mock": "^28.1.3", "jmespath": "^0.16.0", "jquery": "^3.4.1", "jsdom": "19.0.0", @@ -3496,6 +3497,18 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/@jest/environment/node_modules/jest-mock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, "node_modules/@jest/environment/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -3561,6 +3574,18 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/@jest/fake-timers/node_modules/jest-mock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, "node_modules/@jest/fake-timers/node_modules/jest-util": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", @@ -39769,6 +39794,18 @@ "node": ">=0.10.0" } }, + "node_modules/jest-environment-jsdom/node_modules/jest-mock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, "node_modules/jest-environment-jsdom/node_modules/jest-util": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", @@ -39984,6 +40021,18 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/jest-environment-node/node_modules/jest-mock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, "node_modules/jest-environment-node/node_modules/jest-util": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", @@ -40378,36 +40427,37 @@ } }, "node_modules/jest-mock": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", - "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.3.tgz", + "integrity": "sha512-o3J2jr6dMMWYVH4Lh/NKmDXdosrsJgi4AviS8oXLujcjpCMBb1FMsblDnOXKZKfSiHLxYub1eS0IHuRXsio9eA==", "dependencies": { - "@jest/types": "^27.5.1", + "@jest/types": "^28.1.3", "@types/node": "*" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-mock/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", + "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", "dependencies": { + "@jest/schemas": "^28.1.3", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", - "@types/yargs": "^16.0.0", + "@types/yargs": "^17.0.8", "chalk": "^4.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-mock/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", "dependencies": { "@types/yargs-parser": "*" } @@ -41040,6 +41090,18 @@ "fsevents": "^2.3.2" } }, + "node_modules/jest-runtime/node_modules/jest-mock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, "node_modules/jest-runtime/node_modules/jest-regex-util": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", @@ -64044,6 +64106,15 @@ "supports-color": "^7.1.0" } }, + "jest-mock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*" + } + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -64096,6 +64167,15 @@ "supports-color": "^7.1.0" } }, + "jest-mock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*" + } + }, "jest-util": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", @@ -92256,6 +92336,15 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "jest-mock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*" + } + }, "jest-util": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", @@ -93225,6 +93314,15 @@ "supports-color": "^7.1.0" } }, + "jest-mock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*" + } + }, "jest-util": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", @@ -93533,30 +93631,31 @@ } }, "jest-mock": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", - "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.3.tgz", + "integrity": "sha512-o3J2jr6dMMWYVH4Lh/NKmDXdosrsJgi4AviS8oXLujcjpCMBb1FMsblDnOXKZKfSiHLxYub1eS0IHuRXsio9eA==", "requires": { - "@jest/types": "^27.5.1", + "@jest/types": "^28.1.3", "@types/node": "*" }, "dependencies": { "@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", + "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", "requires": { + "@jest/schemas": "^28.1.3", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", - "@types/yargs": "^16.0.0", + "@types/yargs": "^17.0.8", "chalk": "^4.0.0" } }, "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", "requires": { "@types/yargs-parser": "*" } @@ -94046,6 +94145,15 @@ "walker": "^1.0.7" } }, + "jest-mock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*" + } + }, "jest-regex-util": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", diff --git a/packages/cli/package.json b/packages/cli/package.json index 08f4ef6b7ae..206c91c83eb 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -88,6 +88,7 @@ "@types/validator": "^13.7.0", "concurrently": "^5.1.0", "jest": "^27.4.7", + "jest-mock": "^28.1.3", "nodemon": "^2.0.2", "run-script-os": "^1.0.7", "supertest": "^6.2.2", @@ -96,9 +97,9 @@ "typescript": "~4.6.0" }, "dependencies": { - "@oclif/core": "^1.9.3", "@apidevtools/swagger-cli": "4.0.0", "@oclif/command": "^1.5.18", + "@oclif/core": "^1.9.3", "@oclif/errors": "^1.2.2", "@rudderstack/rudder-sdk-node": "1.0.6", "@types/json-diff": "^0.5.1", diff --git a/packages/cli/src/CommunityNodes/helpers.ts b/packages/cli/src/CommunityNodes/helpers.ts index 9fb2199bdd9..b70546ec5cb 100644 --- a/packages/cli/src/CommunityNodes/helpers.ts +++ b/packages/cli/src/CommunityNodes/helpers.ts @@ -1,71 +1,89 @@ +/* eslint-disable no-restricted-syntax */ /* eslint-disable import/no-cycle */ /* eslint-disable @typescript-eslint/naming-convention */ import { promisify } from 'util'; import { exec } from 'child_process'; import { access as fsAccess, mkdir as fsMkdir } from 'fs/promises'; +import axios from 'axios'; import { UserSettings } from 'n8n-core'; import { LoggerProxy, PublicInstalledPackage } from 'n8n-workflow'; -import axios from 'axios'; + import { NODE_PACKAGE_PREFIX, NPM_COMMAND_TOKENS, NPM_PACKAGE_STATUS_GOOD, RESPONSE_ERROR_MESSAGES, + UNKNOWN_FAILURE_REASON, } from '../constants'; -import { NpmPackageStatusCheck, NpmUpdatesAvailable, ParsedNpmPackageName } from '../Interfaces'; import { InstalledPackages } from '../databases/entities/InstalledPackages'; import config from '../../config'; +import type { CommunityPackages } from '../Interfaces'; + +const { + PACKAGE_NAME_NOT_PROVIDED, + DISK_IS_FULL, + PACKAGE_FAILED_TO_INSTALL, + PACKAGE_VERSION_NOT_FOUND, + PACKAGE_DOES_NOT_CONTAIN_NODES, + PACKAGE_NOT_FOUND, +} = RESPONSE_ERROR_MESSAGES; + +const { + NPM_PACKAGE_NOT_FOUND_ERROR, + NPM_NO_VERSION_AVAILABLE, + NPM_DISK_NO_SPACE, + NPM_DISK_INSUFFICIENT_SPACE, + NPM_PACKAGE_VERSION_NOT_FOUND_ERROR, +} = NPM_COMMAND_TOKENS; + const execAsync = promisify(exec); -export const parsePackageName = (originalString: string | undefined): ParsedNpmPackageName => { - if (!originalString) { - throw new Error('Package name was not provided'); - } +const INVALID_OR_SUSPICIOUS_PACKAGE_NAME = /[^0-9a-z@\-./]/; - if (new RegExp(/[^0-9a-z@\-./]/).test(originalString)) { - // Prevent any strings that are not valid npm package names or - // could indicate malicous commands +export const parseNpmPackageName = (rawString?: string): CommunityPackages.ParsedPackageName => { + if (!rawString) throw new Error(PACKAGE_NAME_NOT_PROVIDED); + + if (INVALID_OR_SUSPICIOUS_PACKAGE_NAME.test(rawString)) throw new Error('Package name must be a single word'); - } - const scope = originalString.includes('/') ? originalString.split('/')[0] : undefined; + const scope = rawString.includes('/') ? rawString.split('/')[0] : undefined; - const packageNameWithoutScope = scope ? originalString.replace(`${scope}/`, '') : originalString; + const packageNameWithoutScope = scope ? rawString.replace(`${scope}/`, '') : rawString; if (!packageNameWithoutScope.startsWith(NODE_PACKAGE_PREFIX)) { - throw new Error('Package name must start with n8n-nodes-'); + throw new Error(`Package name must start with ${NODE_PACKAGE_PREFIX}`); } const version = packageNameWithoutScope.includes('@') ? packageNameWithoutScope.split('@')[1] : undefined; - const packageName = version ? originalString.replace(`@${version}`, '') : originalString; + const packageName = version ? rawString.replace(`@${version}`, '') : rawString; return { packageName, scope, version, - originalString, + rawString, }; }; +export const sanitizeNpmPackageName = parseNpmPackageName; + export const executeCommand = async ( command: string, - options?: { - doNotHandleError?: boolean; - }, + options?: { doNotHandleError?: boolean }, ): Promise => { const downloadFolder = UserSettings.getUserN8nFolderDowloadedNodesPath(); - // Make sure the node-download folder exists + try { await fsAccess(downloadFolder); - // eslint-disable-next-line no-empty - } catch (error) { + } catch (_) { await fsMkdir(downloadFolder); } + const execOptions = { cwd: downloadFolder, env: { @@ -76,57 +94,48 @@ export const executeCommand = async ( try { const commandResult = await execAsync(command, execOptions); + return commandResult.stdout; } catch (error) { - if (options?.doNotHandleError) { - throw error; - } - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - const errorMessage = error.message as string; + if (options?.doNotHandleError) throw error; - if ( - errorMessage.includes(NPM_COMMAND_TOKENS.NPM_PACKAGE_NOT_FOUND_ERROR) || - errorMessage.includes(NPM_COMMAND_TOKENS.NPM_NO_VERSION_AVAILABLE) - ) { - throw new Error(RESPONSE_ERROR_MESSAGES.PACKAGE_NOT_FOUND); - } - if (errorMessage.includes(NPM_COMMAND_TOKENS.NPM_PACKAGE_VERSION_NOT_FOUND_ERROR)) { - throw new Error(RESPONSE_ERROR_MESSAGES.PACKAGE_VERSION_NOT_FOUND); - } - if ( - errorMessage.includes(NPM_COMMAND_TOKENS.NPM_DISK_NO_SPACE) || - errorMessage.includes(NPM_COMMAND_TOKENS.NPM_DISK_INSUFFICIENT_SPACE) - ) { - throw new Error(RESPONSE_ERROR_MESSAGES.DISK_IS_FULL); - } + const errorMessage = error instanceof Error ? error.message : UNKNOWN_FAILURE_REASON; - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - LoggerProxy.warn('npm command failed; see message', { errorMessage }); + const map = { + [NPM_PACKAGE_NOT_FOUND_ERROR]: PACKAGE_NOT_FOUND, + [NPM_NO_VERSION_AVAILABLE]: PACKAGE_NOT_FOUND, + [NPM_PACKAGE_VERSION_NOT_FOUND_ERROR]: PACKAGE_VERSION_NOT_FOUND, + [NPM_DISK_NO_SPACE]: DISK_IS_FULL, + [NPM_DISK_INSUFFICIENT_SPACE]: DISK_IS_FULL, + }; - throw new Error('Package could not be installed - check logs for details'); + Object.entries(map).forEach(([npmMessage, n8nMessage]) => { + if (errorMessage.includes(npmMessage)) throw new Error(n8nMessage); + }); + + LoggerProxy.warn('npm command failed', { errorMessage }); + + throw new Error(PACKAGE_FAILED_TO_INSTALL); } }; export function matchPackagesWithUpdates( - installedPackages: InstalledPackages[], - availableUpdates?: NpmUpdatesAvailable, + packages: InstalledPackages[], + updates?: CommunityPackages.AvailableUpdates, ): PublicInstalledPackage[] { - if (!availableUpdates) { - return installedPackages; - } - const hydratedPackageList = [] as PublicInstalledPackage[]; + if (!updates) return packages; - for (let i = 0; i < installedPackages.length; i++) { - const installedPackage = installedPackages[i]; - const publicPackage = { ...installedPackage } as PublicInstalledPackage; + return packages.reduce((acc, cur) => { + const publicPackage: PublicInstalledPackage = { ...cur }; - if (availableUpdates[installedPackage.packageName]) { - publicPackage.updateAvailable = availableUpdates[installedPackage.packageName].latest; - } - hydratedPackageList.push(publicPackage); - } + const update = updates[cur.packageName]; - return hydratedPackageList; + if (update) publicPackage.updateAvailable = update.latest; + + acc.push(publicPackage); + + return acc; + }, []); } export function matchMissingPackages( @@ -138,7 +147,7 @@ export function matchMissingPackages( const missingPackagesList = missingPackageNames.map((missingPackageName: string) => { // Strip away versions but maintain scope and package name try { - const parsedPackageData = parsePackageName(missingPackageName); + const parsedPackageData = parseNpmPackageName(missingPackageName); return parsedPackageData.packageName; // eslint-disable-next-line no-empty @@ -147,6 +156,7 @@ export function matchMissingPackages( }); const hydratedPackageList = [] as PublicInstalledPackage[]; + installedPackages.forEach((installedPackage) => { const hydratedInstalledPackage = { ...installedPackage }; if (missingPackagesList.includes(hydratedInstalledPackage.packageName)) { @@ -158,47 +168,38 @@ export function matchMissingPackages( return hydratedPackageList; } -export async function checkPackageStatus(packageName: string): Promise { - // You can change this URL for testing - the default testing url below - // is a postman mock service - const n8nBackendServiceUrl = 'https://api.n8n.io/api/package'; +export async function checkNpmPackageStatus( + packageName: string, +): Promise { + const N8N_BACKEND_SERVICE_URL = 'https://api.n8n.io/api/package'; try { - const output = await axios.post( - n8nBackendServiceUrl, + const response = await axios.post( + N8N_BACKEND_SERVICE_URL, { name: packageName }, - { - method: 'POST', - }, + { method: 'POST' }, ); - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - if (output.data.status !== NPM_PACKAGE_STATUS_GOOD) { - return output.data as NpmPackageStatusCheck; - } + if (response.data.status !== NPM_PACKAGE_STATUS_GOOD) return response.data; } catch (error) { // Do nothing if service is unreachable } + return { status: NPM_PACKAGE_STATUS_GOOD }; } -export function hasPackageLoadedSuccessfully(packageName: string): boolean { - try { - const failedPackages = (config.get('nodes.packagesMissing') as string).split(' '); +export function hasPackageLoaded(packageName: string): boolean { + const missingPackages = config.get('nodes.packagesMissing') as string | undefined; - const packageFailedToLoad = failedPackages.find( + if (!missingPackages) return true; + + return !missingPackages + .split(' ') + .some( (packageNameAndVersion) => packageNameAndVersion.startsWith(packageName) && packageNameAndVersion.replace(packageName, '').startsWith('@'), ); - if (packageFailedToLoad) { - return false; - } - return true; - } catch (_error) { - // If key doesn't exist it means all packages loaded fine - return true; - } } export function removePackageFromMissingList(packageName: string): void { @@ -216,3 +217,17 @@ export function removePackageFromMissingList(packageName: string): void { // Do nothing } } + +export const isClientError = (error: Error): boolean => { + const clientErrors = [ + PACKAGE_VERSION_NOT_FOUND, + PACKAGE_DOES_NOT_CONTAIN_NODES, + PACKAGE_NOT_FOUND, + ]; + + return clientErrors.some((message) => error.message.includes(message)); +}; + +export function isNpmError(error: unknown): error is { code: number; stdout: string } { + return typeof error === 'object' && error !== null && 'code' in error && 'stdout' in error; +} diff --git a/packages/cli/src/CommunityNodes/packageModel.ts b/packages/cli/src/CommunityNodes/packageModel.ts index 09b858cd6c6..c803d01a12a 100644 --- a/packages/cli/src/CommunityNodes/packageModel.ts +++ b/packages/cli/src/CommunityNodes/packageModel.ts @@ -4,24 +4,25 @@ import { Db } from '..'; import { InstalledNodes } from '../databases/entities/InstalledNodes'; import { InstalledPackages } from '../databases/entities/InstalledPackages'; -export async function searchInstalledPackage( +export async function findInstalledPackage( packageName: string, ): Promise { - const installedPackage = await Db.collections.InstalledPackages.findOne(packageName, { - relations: ['installedNodes'], - }); - return installedPackage; + return Db.collections.InstalledPackages.findOne(packageName, { relations: ['installedNodes'] }); +} + +export async function isPackageInstalled(packageName: string): Promise { + const installedPackage = await findInstalledPackage(packageName); + return installedPackage !== undefined; } export async function getAllInstalledPackages(): Promise { - const installedPackages = await Db.collections.InstalledPackages.find({ - relations: ['installedNodes'], - }); - return installedPackages; + return Db.collections.InstalledPackages.find({ relations: ['installedNodes'] }); } -export async function removePackageFromDatabase(packageName: InstalledPackages): Promise { - void (await Db.collections.InstalledPackages.remove(packageName)); +export async function removePackageFromDatabase( + packageName: InstalledPackages, +): Promise { + return Db.collections.InstalledPackages.remove(packageName); } export async function persistInstalledPackageData( diff --git a/packages/cli/src/Interfaces.ts b/packages/cli/src/Interfaces.ts index 0b81e71112d..aa4150c7ffb 100644 --- a/packages/cli/src/Interfaces.ts +++ b/packages/cli/src/Interfaces.ts @@ -714,30 +714,32 @@ export interface IWorkflowExecuteProcess { export type WhereClause = Record; -/** ******************************** - * Commuinity nodes - ******************************** */ +// ---------------------------------- +// community nodes +// ---------------------------------- -export type ParsedNpmPackageName = { - packageName: string; - originalString: string; - scope?: string; - version?: string; -}; - -export type NpmUpdatesAvailable = { - [packageName: string]: { - current: string; - wanted: string; - latest: string; - location: string; +export namespace CommunityPackages { + export type ParsedPackageName = { + packageName: string; + rawString: string; + scope?: string; + version?: string; }; -}; -export type NpmPackageStatusCheck = { - status: 'OK' | 'Banned'; - reason?: string; -}; + export type AvailableUpdates = { + [packageName: string]: { + current: string; + wanted: string; + latest: string; + location: string; + }; + }; + + export type PackageStatusCheck = { + status: 'OK' | 'Banned'; + reason?: string; + }; +} // ---------------------------------- // telemetry diff --git a/packages/cli/src/ResponseHelper.ts b/packages/cli/src/ResponseHelper.ts index da54dfc52b4..8bc83b4b35d 100644 --- a/packages/cli/src/ResponseHelper.ts +++ b/packages/cli/src/ResponseHelper.ts @@ -35,6 +35,8 @@ export class ResponseError extends Error { /** * Creates an instance of ResponseError. + * Must be used inside a block with `ResponseHelper.send()`. + * * @param {string} message The error message * @param {number} [errorCode] The error code which can be used by frontend to identify the actual error * @param {number} [httpStatusCode] The HTTP status code the response should have diff --git a/packages/cli/src/api/nodes.api.ts b/packages/cli/src/api/nodes.api.ts index f3762c21266..7948489534a 100644 --- a/packages/cli/src/api/nodes.api.ts +++ b/packages/cli/src/api/nodes.api.ts @@ -1,44 +1,44 @@ /* eslint-disable import/no-cycle */ -import express = require('express'); -import { LoggerProxy, PublicInstalledPackage } from 'n8n-workflow'; -import { getLogger } from '../Logger'; +import express from 'express'; +import { PublicInstalledPackage } from 'n8n-workflow'; +import config from '../../config'; import { ResponseHelper, LoadNodesAndCredentials, Push, InternalHooksManager } from '..'; -import { NodeRequest } from '../requests'; -import { RESPONSE_ERROR_MESSAGES } from '../constants'; + +import { RESPONSE_ERROR_MESSAGES, UNKNOWN_FAILURE_REASON } from '../constants'; import { matchMissingPackages, matchPackagesWithUpdates, executeCommand, - checkPackageStatus, - hasPackageLoadedSuccessfully, + checkNpmPackageStatus, + hasPackageLoaded, removePackageFromMissingList, - parsePackageName, + parseNpmPackageName, + isClientError, + sanitizeNpmPackageName, + isNpmError, } from '../CommunityNodes/helpers'; -import { getAllInstalledPackages, searchInstalledPackage } from '../CommunityNodes/packageModel'; +import { + getAllInstalledPackages, + findInstalledPackage, + isPackageInstalled, +} from '../CommunityNodes/packageModel'; import { isAuthenticatedRequest } from '../UserManagement/UserManagementHelper'; -import config = require('../../config'); -import { NpmUpdatesAvailable } from '../Interfaces'; + +import type { NodeRequest } from '../requests'; +import type { CommunityPackages } from '../Interfaces'; +import { InstalledPackages } from '../databases/entities/InstalledPackages'; + +const { PACKAGE_NOT_INSTALLED, PACKAGE_NAME_NOT_PROVIDED } = RESPONSE_ERROR_MESSAGES; export const nodesController = express.Router(); -/** - * Initialize Logger if needed - */ -nodesController.use((req, res, next) => { - try { - LoggerProxy.getInstance(); - } catch (error) { - LoggerProxy.init(getLogger()); - } - next(); -}); - nodesController.use((req, res, next) => { if (!isAuthenticatedRequest(req) || req.user.globalRole.name !== 'owner') { res.status(403).json({ status: 'error', message: 'Unauthorized' }); return; } + next(); }); @@ -50,246 +50,263 @@ nodesController.use((req, res, next) => { }); return; } + next(); }); +/** + * POST /nodes + * + * Install an n8n community package + */ nodesController.post( '/', ResponseHelper.send(async (req: NodeRequest.Post) => { const { name } = req.body; - let parsedPackageName; - try { - parsedPackageName = parsePackageName(name); - } catch (error) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-argument - throw new ResponseHelper.ResponseError(error.message, undefined, 400); + + if (!name) { + throw new ResponseHelper.ResponseError(PACKAGE_NAME_NOT_PROVIDED, undefined, 400); } - // Only install packages that haven't been installed - // or that have failed loading - const installedPackageInstalled = await searchInstalledPackage(parsedPackageName.packageName); - const loadedPackage = hasPackageLoadedSuccessfully(name); - if (installedPackageInstalled && loadedPackage) { + let parsed: CommunityPackages.ParsedPackageName; + + try { + parsed = parseNpmPackageName(name); + } catch (error) { throw new ResponseHelper.ResponseError( - `Package "${parsedPackageName.packageName}" is already installed. For updating, click the corresponding button.`, + error instanceof Error ? error.message : 'Failed to parse package name', undefined, 400, ); } - const packageStatus = await checkPackageStatus(name); + const isInstalled = await isPackageInstalled(parsed.packageName); + const hasLoaded = hasPackageLoaded(name); + + if (isInstalled && hasLoaded) { + throw new ResponseHelper.ResponseError( + [ + `Package "${parsed.packageName}" is already installed`, + 'To update it, click the corresponding button in the UI', + ].join('.'), + undefined, + 400, + ); + } + + const packageStatus = await checkNpmPackageStatus(name); + if (packageStatus.status !== 'OK') { throw new ResponseHelper.ResponseError( - `Package "${name}" has been banned from n8n's repository and will not be installed`, + `Package "${name}" is banned so it cannot be installed`, undefined, 400, ); } + let installedPackage: InstalledPackages; + try { - const installedPackage = await LoadNodesAndCredentials().loadNpmModule( - parsedPackageName.packageName, - parsedPackageName.version, + installedPackage = await LoadNodesAndCredentials().loadNpmModule( + parsed.packageName, + parsed.version, ); - - if (!loadedPackage) { - removePackageFromMissingList(name); - } - - // Inform the connected frontends that new nodes are available - installedPackage.installedNodes.forEach((nodeData) => { - const pushInstance = Push.getInstance(); - pushInstance.send('reloadNodeType', { - name: nodeData.type, - version: nodeData.latestVersion, - }); - }); - - void InternalHooksManager.getInstance().onCommunityPackageInstallFinished({ - user_id: req.user.id, - input_string: name, - package_name: parsedPackageName.packageName, - success: true, - package_version: parsedPackageName.version, - package_node_names: installedPackage.installedNodes.map((nodeData) => nodeData.name), - package_author: installedPackage.authorName, - package_author_email: installedPackage.authorEmail, - }); - - return installedPackage; } catch (error) { - let statusCode = 500; - // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access - const errorMessage = error.message as string; - if ( - errorMessage.includes(RESPONSE_ERROR_MESSAGES.PACKAGE_VERSION_NOT_FOUND) || - errorMessage.includes(RESPONSE_ERROR_MESSAGES.PACKAGE_DOES_NOT_CONTAIN_NODES) || - errorMessage.includes(RESPONSE_ERROR_MESSAGES.PACKAGE_NOT_FOUND) - ) { - statusCode = 400; - } + const errorMessage = error instanceof Error ? error.message : UNKNOWN_FAILURE_REASON; void InternalHooksManager.getInstance().onCommunityPackageInstallFinished({ user_id: req.user.id, input_string: name, - package_name: parsedPackageName.packageName, + package_name: parsed.packageName, success: false, - package_version: parsedPackageName.version, + package_version: parsed.version, failure_reason: errorMessage, }); - throw new ResponseHelper.ResponseError( - `Error loading package "${name}": ${errorMessage}`, - undefined, - statusCode, - ); + + const message = [`Error loading package "${name}"`, errorMessage].join(':'); + + const clientError = error instanceof Error ? isClientError(error) : false; + + throw new ResponseHelper.ResponseError(message, undefined, clientError ? 400 : 500); } + + if (!hasLoaded) removePackageFromMissingList(name); + + const pushInstance = Push.getInstance(); + + // broadcast to connected frontends that node list has been updated + installedPackage.installedNodes.forEach((node) => { + pushInstance.send('reloadNodeType', { + name: node.type, + version: node.latestVersion, + }); + }); + + void InternalHooksManager.getInstance().onCommunityPackageInstallFinished({ + user_id: req.user.id, + input_string: name, + package_name: parsed.packageName, + success: true, + package_version: parsed.version, + package_node_names: installedPackage.installedNodes.map((node) => node.name), + package_author: installedPackage.authorName, + package_author_email: installedPackage.authorEmail, + }); + + return installedPackage; }), ); -// Install new credentials/nodes from npm +/** + * GET /nodes + * + * Retrieve list of installed n8n community packages + */ nodesController.get( '/', ResponseHelper.send(async (): Promise => { - const packages = await getAllInstalledPackages(); + const installedPackages = await getAllInstalledPackages(); - if (packages.length === 0) { - return packages; - } + if (installedPackages.length === 0) return []; + + let pendingUpdates: CommunityPackages.AvailableUpdates | undefined; - let pendingUpdates: NpmUpdatesAvailable | undefined; try { - // Command succeeds when there are no updates. - // NPM handles this oddly. It exits with code 1 when there are updates. - // More here: https://github.com/npm/rfcs/issues/473 - await executeCommand('npm outdated --json', { doNotHandleError: true }); + const command = ['npm', 'outdated', '--json'].join(' '); + await executeCommand(command, { doNotHandleError: true }); } catch (error) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access - if (error.code === 1) { - // Updates available - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-argument - pendingUpdates = JSON.parse(error.stdout); + // when there are updates, npm exits with code 1 + // when there are no updates, command succeeds + // https://github.com/npm/rfcs/issues/473 + + if (isNpmError(error) && error.code === 1) { + pendingUpdates = JSON.parse(error.stdout) as CommunityPackages.AvailableUpdates; } } - let hydratedPackages = matchPackagesWithUpdates(packages, pendingUpdates); + + let hydratedPackages = matchPackagesWithUpdates(installedPackages, pendingUpdates); + try { - if (config.get('nodes.packagesMissing')) { - // eslint-disable-next-line prettier/prettier, @typescript-eslint/no-unsafe-argument - hydratedPackages = matchMissingPackages(hydratedPackages, config.get('nodes.packagesMissing')); + const missingPackages = config.get('nodes.packagesMissing') as string | undefined; + + if (missingPackages) { + hydratedPackages = matchMissingPackages(hydratedPackages, missingPackages); } - } catch (error) { + } catch (_) { // Do nothing if setting is missing } + return hydratedPackages; }), ); -// Uninstall credentials/nodes from npm +/** + * DELETE /nodes + * + * Uninstall an installed n8n community package + */ nodesController.delete( '/', ResponseHelper.send(async (req: NodeRequest.Delete) => { const { name } = req.body; + if (!name) { - throw new ResponseHelper.ResponseError( - RESPONSE_ERROR_MESSAGES.PACKAGE_NAME_NOT_PROVIDED, - undefined, - 400, - ); - } - // This function also sanitizes the package name by throwing errors. - parsePackageName(name); - - const installedPackage = await searchInstalledPackage(name); - - if (!installedPackage) { - throw new ResponseHelper.ResponseError( - RESPONSE_ERROR_MESSAGES.PACKAGE_NOT_INSTALLED, - undefined, - 400, - ); + throw new ResponseHelper.ResponseError(PACKAGE_NAME_NOT_PROVIDED, undefined, 400); } try { - void (await LoadNodesAndCredentials().removeNpmModule(name, installedPackage)); - - // Inform the connected frontends that the node list has been updated - installedPackage.installedNodes.forEach((installedNode) => { - const pushInstance = Push.getInstance(); - pushInstance.send('removeNodeType', { - name: installedNode.type, - version: installedNode.latestVersion, - }); - }); - - void InternalHooksManager.getInstance().onCommunityPackageDeleteFinished({ - user_id: req.user.id, - package_name: name, - package_version: installedPackage.installedVersion, - package_node_names: installedPackage.installedNodes.map((nodeData) => nodeData.name), - package_author: installedPackage.authorName, - package_author_email: installedPackage.authorEmail, - }); + sanitizeNpmPackageName(name); } catch (error) { - throw new ResponseHelper.ResponseError( - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions, @typescript-eslint/no-unsafe-member-access - `Error removing package "${name}": ${error.message}`, - undefined, - 500, - ); + const message = error instanceof Error ? error.message : UNKNOWN_FAILURE_REASON; + + throw new ResponseHelper.ResponseError(message, undefined, 400); } + + const installedPackage = await findInstalledPackage(name); + + if (!installedPackage) { + throw new ResponseHelper.ResponseError(PACKAGE_NOT_INSTALLED, undefined, 400); + } + + try { + await LoadNodesAndCredentials().removeNpmModule(name, installedPackage); + } catch (error) { + const message = [ + `Error removing package "${name}"`, + error instanceof Error ? error.message : UNKNOWN_FAILURE_REASON, + ].join(':'); + + throw new ResponseHelper.ResponseError(message, undefined, 500); + } + + const pushInstance = Push.getInstance(); + + // broadcast to connected frontends that node list has been updated + installedPackage.installedNodes.forEach((node) => { + pushInstance.send('removeNodeType', { + name: node.type, + version: node.latestVersion, + }); + }); + + void InternalHooksManager.getInstance().onCommunityPackageDeleteFinished({ + user_id: req.user.id, + package_name: name, + package_version: installedPackage.installedVersion, + package_node_names: installedPackage.installedNodes.map((node) => node.name), + package_author: installedPackage.authorName, + package_author_email: installedPackage.authorEmail, + }); }), ); -// Update a package +/** + * PATCH /nodes + * + * Update an installed n8n community package + */ nodesController.patch( '/', ResponseHelper.send(async (req: NodeRequest.Update) => { const { name } = req.body; + if (!name) { - throw new ResponseHelper.ResponseError( - RESPONSE_ERROR_MESSAGES.PACKAGE_NAME_NOT_PROVIDED, - undefined, - 400, - ); + throw new ResponseHelper.ResponseError(PACKAGE_NAME_NOT_PROVIDED, undefined, 400); } - const parsedPackageData = parsePackageName(name); - const packagePreviouslyInstalled = await searchInstalledPackage(name); + const previouslyInstalledPackage = await findInstalledPackage(name); - if (!packagePreviouslyInstalled) { - throw new ResponseHelper.ResponseError( - RESPONSE_ERROR_MESSAGES.PACKAGE_NOT_INSTALLED, - undefined, - 400, - ); + if (!previouslyInstalledPackage) { + throw new ResponseHelper.ResponseError(PACKAGE_NOT_INSTALLED, undefined, 400); } try { const newInstalledPackage = await LoadNodesAndCredentials().updateNpmModule( - parsedPackageData.packageName, - packagePreviouslyInstalled, + parseNpmPackageName(name).packageName, + previouslyInstalledPackage, ); const pushInstance = Push.getInstance(); - // Inform the connected frontends that new nodes are available - packagePreviouslyInstalled.installedNodes.forEach((installedNode) => { + // broadcast to connected frontends that node list has been updated + previouslyInstalledPackage.installedNodes.forEach((node) => { pushInstance.send('removeNodeType', { - name: installedNode.type, - version: installedNode.latestVersion, + name: node.type, + version: node.latestVersion, }); }); - newInstalledPackage.installedNodes.forEach((nodeData) => { + newInstalledPackage.installedNodes.forEach((node) => { pushInstance.send('reloadNodeType', { - name: nodeData.name, - version: nodeData.latestVersion, + name: node.name, + version: node.latestVersion, }); }); void InternalHooksManager.getInstance().onCommunityPackageUpdateFinished({ user_id: req.user.id, package_name: name, - package_version_current: packagePreviouslyInstalled.installedVersion, + package_version_current: previouslyInstalledPackage.installedVersion, package_version_new: newInstalledPackage.installedVersion, package_node_names: newInstalledPackage.installedNodes.map((node) => node.name), package_author: newInstalledPackage.authorName, @@ -298,19 +315,20 @@ nodesController.patch( return newInstalledPackage; } catch (error) { - packagePreviouslyInstalled.installedNodes.forEach((installedNode) => { + previouslyInstalledPackage.installedNodes.forEach((node) => { const pushInstance = Push.getInstance(); pushInstance.send('removeNodeType', { - name: installedNode.type, - version: installedNode.latestVersion, + name: node.type, + version: node.latestVersion, }); }); - throw new ResponseHelper.ResponseError( - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions, @typescript-eslint/no-unsafe-member-access - `Error updating package "${name}": ${error.message}`, - undefined, - 500, - ); + + const message = [ + `Error removing package "${name}"`, + error instanceof Error ? error.message : UNKNOWN_FAILURE_REASON, + ].join(':'); + + throw new ResponseHelper.ResponseError(message, undefined, 500); } }), ); diff --git a/packages/cli/src/constants.ts b/packages/cli/src/constants.ts index 409d16d3108..b6cd214f621 100644 --- a/packages/cli/src/constants.ts +++ b/packages/cli/src/constants.ts @@ -12,6 +12,7 @@ export const RESPONSE_ERROR_MESSAGES = { PACKAGE_NAME_NOT_PROVIDED: 'Package name is required', PACKAGE_NAME_NOT_VALID: `Package name is not valid - it must start with "${NODE_PACKAGE_PREFIX}"`, PACKAGE_NOT_INSTALLED: 'This package is not installed - you must install it first', + PACKAGE_FAILED_TO_INSTALL: 'Package could not be installed - check logs for details', PACKAGE_NOT_FOUND: 'Package not found in npm', PACKAGE_VERSION_NOT_FOUND: 'The specified package version was not found', PACKAGE_DOES_NOT_CONTAIN_NODES: 'The specified package does not contain any nodes', @@ -29,3 +30,5 @@ export const NPM_COMMAND_TOKENS = { }; export const NPM_PACKAGE_STATUS_GOOD = 'OK'; + +export const UNKNOWN_FAILURE_REASON = 'Unknown failure reason'; diff --git a/packages/cli/src/requests.d.ts b/packages/cli/src/requests.d.ts index a6909f7e540..2f486a66b2b 100644 --- a/packages/cli/src/requests.d.ts +++ b/packages/cli/src/requests.d.ts @@ -286,21 +286,21 @@ export type NodeParameterOptionsRequest = AuthenticatedRequest< >; // ---------------------------------- -// /tags +// /tags // ---------------------------------- export declare namespace TagsRequest { type Delete = AuthenticatedRequest<{ id: string }>; } -export declare namespace NodeRequest { - type RequestBody = { - name: string; - }; +// ---------------------------------- +// /nodes +// ---------------------------------- +export declare namespace NodeRequest { type GetAll = AuthenticatedRequest; - type Post = AuthenticatedRequest<{}, {}, RequestBody>; + type Post = AuthenticatedRequest<{}, {}, { name?: string }>; type Delete = Post; diff --git a/packages/cli/test/integration/nodes.api.test.ts b/packages/cli/test/integration/nodes.api.test.ts index 6f7eee4b0a3..3b7ba3b859b 100644 --- a/packages/cli/test/integration/nodes.api.test.ts +++ b/packages/cli/test/integration/nodes.api.test.ts @@ -1,341 +1,333 @@ -import { exec } from 'child_process'; +import path from 'path'; + import express from 'express'; +import { mocked } from 'jest-mock'; + import * as utils from './shared/utils'; -import type { InstalledNodePayload, InstalledPackagePayload } from './shared/types'; -import type { Role } from '../../src/databases/entities/Role'; -import type { User } from '../../src/databases/entities/User'; import * as testDb from './shared/testDb'; - -jest.mock('../../src/CommunityNodes/helpers', () => ({ - matchPackagesWithUpdates: jest.requireActual('../../src/CommunityNodes/helpers').matchPackagesWithUpdates, - parsePackageName: jest.requireActual('../../src/CommunityNodes/helpers').parsePackageName, - hasPackageLoadedSuccessfully: jest.fn(), - searchInstalledPackage: jest.fn(), - executeCommand: jest.fn(), - checkPackageStatus: jest.fn(), - removePackageFromMissingList: jest.fn(), -})); - -jest.mock('../../src/CommunityNodes/packageModel', () => ({ - getAllInstalledPackages: jest.requireActual('../../src/CommunityNodes/packageModel').getAllInstalledPackages, - removePackageFromDatabase: jest.fn(), - searchInstalledPackage: jest.fn(), -})); - -import { executeCommand, checkPackageStatus, hasPackageLoadedSuccessfully, removePackageFromMissingList } from '../../src/CommunityNodes/helpers'; -import { getAllInstalledPackages, searchInstalledPackage, removePackageFromDatabase } from '../../src/CommunityNodes/packageModel'; +import { + executeCommand, + checkNpmPackageStatus, + hasPackageLoaded, + removePackageFromMissingList, + isNpmError, +} from '../../src/CommunityNodes/helpers'; +import { findInstalledPackage, isPackageInstalled } from '../../src/CommunityNodes/packageModel'; import { CURRENT_PACKAGE_VERSION, UPDATED_PACKAGE_VERSION } from './shared/constants'; -import { installedPackagePayload } from './shared/utils'; +import { LoadNodesAndCredentials } from '../../src/LoadNodesAndCredentials'; +import { InstalledPackages } from '../../src/databases/entities/InstalledPackages'; + +import type { Role } from '../../src/databases/entities/Role'; +import type { AuthAgent } from './shared/types'; +import type { InstalledNodes } from '../../src/databases/entities/InstalledNodes'; jest.mock('../../src/telemetry'); -jest.mock('../../src/LoadNodesAndCredentials', () => ({ - LoadNodesAndCredentials: jest.fn(), -})); -import { LoadNodesAndCredentials } from '../../src/LoadNodesAndCredentials'; +jest.mock('../../src/CommunityNodes/helpers', () => { + return { + ...jest.requireActual('../../src/CommunityNodes/helpers'), + checkNpmPackageStatus: jest.fn(), + executeCommand: jest.fn(), + hasPackageLoaded: jest.fn(), + isNpmError: jest.fn(), + removePackageFromMissingList: jest.fn(), + }; +}); +jest.mock('../../src/CommunityNodes/packageModel', () => { + return { + ...jest.requireActual('../../src/CommunityNodes/packageModel'), + isPackageInstalled: jest.fn(), + findInstalledPackage: jest.fn(), + }; +}); +const mockedEmptyPackage = mocked(utils.emptyPackage); let app: express.Application; let testDbName = ''; let globalOwnerRole: Role; -let globalMemberRole: Role; -let ownerShell: User; +let authAgent: AuthAgent; beforeAll(async () => { app = await utils.initTestServer({ endpointGroups: ['nodes'], applyAuth: true }); const initResult = await testDb.init(); testDbName = initResult.testDbName; - utils.initConfigFile(); - globalOwnerRole = await testDb.getGlobalOwnerRole(); - globalMemberRole = await testDb.getGlobalMemberRole(); - ownerShell = await testDb.createUserShell(globalOwnerRole); + authAgent = utils.createAuthAgent(app); + + utils.initConfigFile(); utils.initTestLogger(); utils.initTestTelemetry(); }); beforeEach(async () => { await testDb.truncate(['InstalledNodes', 'InstalledPackages'], testDbName); - // @ts-ignore - executeCommand.mockReset(); - // @ts-ignore - checkPackageStatus.mockReset(); - // @ts-ignore - searchInstalledPackage.mockReset(); - // @ts-ignore - hasPackageLoadedSuccessfully.mockReset(); + + mocked(executeCommand).mockReset(); + mocked(findInstalledPackage).mockReset(); }); afterAll(async () => { await testDb.terminate(testDbName); }); -test('GET /nodes should return empty list when no nodes are installed', async () => { - const authOwnerAgent = utils.createAgent(app, { auth: true, user: ownerShell }); +/** + * GET /nodes + */ - const response = await authOwnerAgent.get('/nodes').send(); +test('GET /nodes should respond 200 if no nodes are installed', async () => { + const ownerShell = await testDb.createUserShell(globalOwnerRole); - expect(response.statusCode).toBe(200); - expect(response.body.data).toHaveLength(0); + const { + statusCode, + body: { data }, + } = await authAgent(ownerShell).get('/nodes'); + + expect(statusCode).toBe(200); + expect(data).toHaveLength(0); }); -test('GET /nodes should return list with installed package and node', async () => { - const authOwnerAgent = utils.createAgent(app, { auth: true, user: ownerShell }); - const installedPackage = await saveMockPackage(installedPackagePayload()); - await saveMockNode(utils.installedNodePayload(installedPackage.packageName)); +test('GET /nodes should return list of one installed package and node', async () => { + const ownerShell = await testDb.createUserShell(globalOwnerRole); - const response = await authOwnerAgent.get('/nodes').send(); + const { packageName } = await testDb.saveInstalledPackage(utils.installedPackagePayload()); + await testDb.saveInstalledNode(utils.installedNodePayload(packageName)); - expect(response.statusCode).toBe(200); - expect(response.body.data).toHaveLength(1); - expect(response.body.data[0].installedNodes).toHaveLength(1); + const { + statusCode, + body: { data }, + } = await authAgent(ownerShell).get('/nodes'); + + expect(statusCode).toBe(200); + expect(data).toHaveLength(1); + expect(data[0].installedNodes).toHaveLength(1); }); -test('GET /nodes should return list with multiple installed package and node', async () => { - const authOwnerAgent = utils.createAgent(app, { auth: true, user: ownerShell }); - const installedPackage1 = await saveMockPackage(installedPackagePayload()); - await saveMockNode(utils.installedNodePayload(installedPackage1.packageName)); +test('GET /nodes should return list of multiple installed packages and nodes', async () => { + const ownerShell = await testDb.createUserShell(globalOwnerRole); - const installedPackage2 = await saveMockPackage(installedPackagePayload()); - await saveMockNode(utils.installedNodePayload(installedPackage2.packageName)); - await saveMockNode(utils.installedNodePayload(installedPackage2.packageName)); + const first = await testDb.saveInstalledPackage(utils.installedPackagePayload()); + await testDb.saveInstalledNode(utils.installedNodePayload(first.packageName)); - const response = await authOwnerAgent.get('/nodes').send(); + const second = await testDb.saveInstalledPackage(utils.installedPackagePayload()); + await testDb.saveInstalledNode(utils.installedNodePayload(second.packageName)); + await testDb.saveInstalledNode(utils.installedNodePayload(second.packageName)); - expect(response.statusCode).toBe(200); - expect(response.body.data).toHaveLength(2); - expect([...response.body.data[0].installedNodes, ...response.body.data[1].installedNodes]).toHaveLength(3); + const { + statusCode, + body: { data }, + } = await authAgent(ownerShell).get('/nodes'); + + expect(statusCode).toBe(200); + expect(data).toHaveLength(2); + + const allNodes = data.reduce( + (acc: InstalledNodes[], cur: InstalledPackages) => acc.concat(cur.installedNodes), + [], + ); + + expect(allNodes).toHaveLength(3); }); -test('GET /nodes should not check for updates when there are no packages installed', async () => { - const authOwnerAgent = utils.createAgent(app, { auth: true, user: ownerShell }); +test('GET /nodes should not check for updates if no packages installed', async () => { + const ownerShell = await testDb.createUserShell(globalOwnerRole); - await authOwnerAgent.get('/nodes').send(); + await authAgent(ownerShell).get('/nodes'); - expect(executeCommand).toHaveBeenCalledTimes(0); + expect(mocked(executeCommand)).toHaveBeenCalledTimes(0); }); -test('GET /nodes should check for updates when there are packages installed', async () => { - const authOwnerAgent = utils.createAgent(app, { auth: true, user: ownerShell }); - const installedPackage = await saveMockPackage(installedPackagePayload()); - await saveMockNode(utils.installedNodePayload(installedPackage.packageName)); +test('GET /nodes should check for updates if packages installed', async () => { + const ownerShell = await testDb.createUserShell(globalOwnerRole); - await authOwnerAgent.get('/nodes').send(); + const { packageName } = await testDb.saveInstalledPackage(utils.installedPackagePayload()); + await testDb.saveInstalledNode(utils.installedNodePayload(packageName)); - expect(executeCommand).toHaveBeenCalledWith('npm outdated --json', {"doNotHandleError": true}); + await authAgent(ownerShell).get('/nodes'); + + expect(mocked(executeCommand)).toHaveBeenCalledWith('npm outdated --json', { + doNotHandleError: true, + }); }); -test('GET /nodes should mention updates when available', async () => { - const authOwnerAgent = utils.createAgent(app, { auth: true, user: ownerShell }); - const installedPackage = await saveMockPackage(installedPackagePayload()); - await saveMockNode(utils.installedNodePayload(installedPackage.packageName)); +test('GET /nodes should report package updates if available', async () => { + const ownerShell = await testDb.createUserShell(globalOwnerRole); - // @ts-ignore - executeCommand.mockImplementation(() => { - throw getNpmOutdatedError(installedPackage.packageName); + const { packageName } = await testDb.saveInstalledPackage(utils.installedPackagePayload()); + await testDb.saveInstalledNode(utils.installedNodePayload(packageName)); + + mocked(executeCommand).mockImplementationOnce(() => { + throw { + code: 1, + stdout: JSON.stringify({ + [packageName]: { + current: CURRENT_PACKAGE_VERSION, + wanted: CURRENT_PACKAGE_VERSION, + latest: UPDATED_PACKAGE_VERSION, + location: path.join('node_modules', packageName), + }, + }), + }; }); - const response = await authOwnerAgent.get('/nodes').send(); - expect(response.body.data[0].installedVersion).toBe(CURRENT_PACKAGE_VERSION); - expect(response.body.data[0].updateAvailable).toBe(UPDATED_PACKAGE_VERSION); + mocked(isNpmError).mockReturnValueOnce(true); + + const { + body: { data }, + } = await authAgent(ownerShell).get('/nodes'); + + expect(data[0].installedVersion).toBe(CURRENT_PACKAGE_VERSION); + expect(data[0].updateAvailable).toBe(UPDATED_PACKAGE_VERSION); }); -// TEST POST ENDPOINT +/** + * POST /nodes + */ -test('POST /nodes package name should not be empty', async () => { - const authOwnerAgent = utils.createAgent(app, { auth: true, user: ownerShell }); - const response = await authOwnerAgent.post('/nodes').send(); +test('POST /nodes should reject if package name is missing', async () => { + const ownerShell = await testDb.createUserShell(globalOwnerRole); + + const { statusCode } = await authAgent(ownerShell).post('/nodes'); + + expect(statusCode).toBe(400); +}); + +test('POST /nodes should reject if package is duplicate', async () => { + const ownerShell = await testDb.createUserShell(globalOwnerRole); + + mocked(findInstalledPackage).mockResolvedValueOnce(new InstalledPackages()); + mocked(isPackageInstalled).mockResolvedValueOnce(true); + mocked(hasPackageLoaded).mockReturnValueOnce(true); + + const { + statusCode, + body: { message }, + } = await authAgent(ownerShell).post('/nodes').send({ + name: utils.installedPackagePayload().packageName, + }); + + expect(statusCode).toBe(400); + expect(message).toContain('already installed'); +}); + +test('POST /nodes should allow installing packages that could not be loaded', async () => { + const ownerShell = await testDb.createUserShell(globalOwnerRole); + + mocked(findInstalledPackage).mockResolvedValueOnce(new InstalledPackages()); + mocked(hasPackageLoaded).mockReturnValueOnce(false); + mocked(checkNpmPackageStatus).mockResolvedValueOnce({ status: 'OK' }); + + jest + .spyOn(LoadNodesAndCredentials(), 'loadNpmModule') + .mockImplementationOnce(mockedEmptyPackage); + + const { statusCode } = await authAgent(ownerShell).post('/nodes').send({ + name: utils.installedPackagePayload().packageName, + }); + + expect(statusCode).toBe(200); + expect(mocked(removePackageFromMissingList)).toHaveBeenCalled(); +}); + +test('POST /nodes should not install a banned package', async () => { + const ownerShell = await testDb.createUserShell(globalOwnerRole); + mocked(checkNpmPackageStatus).mockResolvedValueOnce({ status: 'Banned' }); + + const { + statusCode, + body: { message }, + } = await authAgent(ownerShell).post('/nodes').send({ + name: utils.installedPackagePayload().packageName, + }); + + expect(statusCode).toBe(400); + expect(message).toContain('banned'); +}); + +/** + * DELETE /nodes + */ + +test('DELETE /nodes should not delete if package name is empty', async () => { + const ownerShell = await testDb.createUserShell(globalOwnerRole); + + const response = await authAgent(ownerShell).delete('/nodes'); expect(response.statusCode).toBe(400); }); -test('POST /nodes Should not install duplicate packages', async () => { - const authOwnerAgent = utils.createAgent(app, { auth: true, user: ownerShell }); - const requestBody = { - name: installedPackagePayload().packageName, - }; - // @ts-ignore - searchInstalledPackage.mockImplementation(() => { - return true; - }); - // @ts-ignore - hasPackageLoadedSuccessfully.mockImplementation(() => { - return true; +test('DELETE /nodes should reject if package is not installed', async () => { + const ownerShell = await testDb.createUserShell(globalOwnerRole); + + const { + statusCode, + body: { message }, + } = await authAgent(ownerShell).delete('/nodes').send({ + name: utils.installedPackagePayload().packageName, }); - const response = await authOwnerAgent.post('/nodes').send(requestBody); - expect(response.status).toBe(400); - expect(response.body.message).toContain('already installed'); + expect(statusCode).toBe(400); + expect(message).toContain('not installed'); }); -test('POST /nodes Should allow installing packages that could not be loaded', async () => { - const authOwnerAgent = utils.createAgent(app, { auth: true, user: ownerShell }); - const requestBody = { - name: installedPackagePayload().packageName, - }; - // @ts-ignore - searchInstalledPackage.mockImplementation(() => { - return true; - }); - // @ts-ignore - hasPackageLoadedSuccessfully.mockImplementation(() => { - return false; +test('DELETE /nodes should uninstall package', async () => { + const ownerShell = await testDb.createUserShell(globalOwnerRole); + + const removeSpy = jest + .spyOn(LoadNodesAndCredentials(), 'removeNpmModule') + .mockImplementationOnce(jest.fn()); + + mocked(findInstalledPackage).mockImplementationOnce(mockedEmptyPackage); + + const { statusCode } = await authAgent(ownerShell).delete('/nodes').send({ + name: utils.installedPackagePayload().packageName, }); - // @ts-ignore - checkPackageStatus.mockImplementation(() => { - return {status:'OK'}; - }); - - // @ts-ignore - LoadNodesAndCredentials.mockImplementation(() => { - return { - loadNpmModule: () => { - return { - installedNodes: [], - }; - }, - }; - }); - - const response = await authOwnerAgent.post('/nodes').send(requestBody); - - expect(removePackageFromMissingList).toHaveBeenCalled(); - expect(response.status).toBe(200); + expect(statusCode).toBe(200); + expect(removeSpy).toHaveBeenCalledTimes(1); }); -test('POST /nodes package should not install banned package', async () => { - const authOwnerAgent = utils.createAgent(app, { auth: true, user: ownerShell }); - const installedPackage = installedPackagePayload(); - const requestBody = { - name: installedPackage.packageName, - }; +/** + * PATCH /nodes + */ - // @ts-ignore - checkPackageStatus.mockImplementation(() => { - return {status:'Banned'}; - }); - const response = await authOwnerAgent.post('/nodes').send(requestBody); - expect(response.statusCode).toBe(400); - expect(response.body.message).toContain('banned'); -}); +test('PATCH /nodes should reject if package name is empty', async () => { + const ownerShell = await testDb.createUserShell(globalOwnerRole); -// TEST DELETE ENDPOINT -test('DELETE /nodes package name should not be empty', async () => { - const authOwnerAgent = utils.createAgent(app, { auth: true, user: ownerShell }); - const response = await authOwnerAgent.delete('/nodes').send(); + const response = await authAgent(ownerShell).patch('/nodes'); expect(response.statusCode).toBe(400); }); -test('DELETE /nodes Should return error when package was not installed', async () => { - const authOwnerAgent = utils.createAgent(app, { auth: true, user: ownerShell }); - const requestBody = { - name: installedPackagePayload().packageName, - }; +test('PATCH /nodes reject if package is not installed', async () => { + const ownerShell = await testDb.createUserShell(globalOwnerRole); - const response = await authOwnerAgent.delete('/nodes').send(requestBody); - expect(response.status).toBe(400); - expect(response.body.message).toContain('not installed'); -}); - -// Useful test ? -test('DELETE /nodes package should be uninstall all conditions are true', async () => { - const authOwnerAgent = utils.createAgent(app, { auth: true, user: ownerShell }); - const requestBody = { - name: installedPackagePayload().packageName, - }; - // @ts-ignore - searchInstalledPackage.mockImplementation(() => { - return { - installedNodes: [], - }; + const { + statusCode, + body: { message }, + } = await authAgent(ownerShell).patch('/nodes').send({ + name: utils.installedPackagePayload().packageName, }); - const removeNpmModuleMock = jest.fn(); - // @ts-ignore - LoadNodesAndCredentials.mockImplementation(() => { - return { - removeNpmModule: removeNpmModuleMock, - }; + expect(statusCode).toBe(400); + expect(message).toContain('not installed'); +}); + +test('PATCH /nodes should update a package', async () => { + const ownerShell = await testDb.createUserShell(globalOwnerRole); + + const updateSpy = jest + .spyOn(LoadNodesAndCredentials(), 'updateNpmModule') + .mockImplementationOnce(mockedEmptyPackage); + + mocked(findInstalledPackage).mockImplementationOnce(mockedEmptyPackage); + + await authAgent(ownerShell).patch('/nodes').send({ + name: utils.installedPackagePayload().packageName, }); - const response = await authOwnerAgent.delete('/nodes').send(requestBody); - expect(response.statusCode).toBe(200); - expect(removeNpmModuleMock).toHaveBeenCalledTimes(1); + expect(updateSpy).toHaveBeenCalledTimes(1); }); - -// TEST PATCH ENDPOINT - -test('PATCH /nodes package name should not be empty', async () => { - const authOwnerAgent = utils.createAgent(app, { auth: true, user: ownerShell }); - const response = await authOwnerAgent.patch('/nodes').send(); - - expect(response.statusCode).toBe(400); -}); - -test('PATCH /nodes Should return error when package was not installed', async () => { - const authOwnerAgent = utils.createAgent(app, { auth: true, user: ownerShell }); - const requestBody = { - name: installedPackagePayload().packageName, - }; - - const response = await authOwnerAgent.patch('/nodes').send(requestBody); - expect(response.status).toBe(400); - expect(response.body.message).toContain('not installed'); -}); - -test('PATCH /nodes package should be updated if all conditions are true', async () => { - const authOwnerAgent = utils.createAgent(app, { auth: true, user: ownerShell }); - const requestBody = { - name: installedPackagePayload().packageName, - }; - // @ts-ignore - searchInstalledPackage.mockImplementation(() => { - return { - installedNodes: [], - }; - }); - - const updatedNpmModuleMock = jest.fn(() => ({ - installedNodes: [], - })); - - // @ts-ignore - LoadNodesAndCredentials.mockImplementation(() => { - return { - updateNpmModule: updatedNpmModuleMock, - }; - }); - - const response = await authOwnerAgent.patch('/nodes').send(requestBody); - expect(updatedNpmModuleMock).toHaveBeenCalledTimes(1); -}); - -async function saveMockPackage(payload: InstalledPackagePayload) { - return await testDb.saveInstalledPackage(payload); -} - -async function saveMockNode(payload: InstalledNodePayload) { - return await testDb.saveInstalledNode(payload); -} - -function getNpmOutdatedError(packageName: string) { - const errorOutput = new Error('Something went wrong'); - // @ts-ignore - errorOutput.code = 1; - // @ts-ignore - errorOutput.stdout = '{' + - `"${packageName}": {` + - `"current": "${CURRENT_PACKAGE_VERSION}",` + - `"wanted": "${CURRENT_PACKAGE_VERSION}",` + - `"latest": "${UPDATED_PACKAGE_VERSION}",` + - `"location": "node_modules/${packageName}"` + - '}' + - '}'; - - return errorOutput; -} diff --git a/packages/cli/test/integration/shared/types.d.ts b/packages/cli/test/integration/shared/types.d.ts index 13fdc9ac551..b8999cae7f6 100644 --- a/packages/cli/test/integration/shared/types.d.ts +++ b/packages/cli/test/integration/shared/types.d.ts @@ -1,4 +1,6 @@ import type { ICredentialDataDecryptedObject, ICredentialNodeAccess } from 'n8n-workflow'; +import type { SuperAgentTest } from 'supertest'; + import type { ICredentialsDb, IDatabaseCollections } from '../../../src'; import type { CredentialsEntity } from '../../../src/databases/entities/CredentialsEntity'; import type { User } from '../../../src/databases/entities/User'; @@ -10,6 +12,8 @@ export type MappingName = keyof typeof MAPPING_TABLES; export type ApiPath = 'internal' | 'public'; +export type AuthAgent = (user: User) => SuperAgentTest; + type EndpointGroup = | 'me' | 'users' @@ -49,12 +53,11 @@ export interface TriggerTime { export type InstalledPackagePayload = { packageName: string; installedVersion: string; -} +}; export type InstalledNodePayload = { name: string; type: string; latestVersion: string; package: string; -} - +}; diff --git a/packages/cli/test/integration/shared/utils.ts b/packages/cli/test/integration/shared/utils.ts index ff744ab5bcb..252ffcf2504 100644 --- a/packages/cli/test/integration/shared/utils.ts +++ b/packages/cli/test/integration/shared/utils.ts @@ -23,7 +23,12 @@ import { } from 'n8n-workflow'; import config from '../../../config'; -import { AUTHLESS_ENDPOINTS, CURRENT_PACKAGE_VERSION, PUBLIC_API_REST_PATH_SEGMENT, REST_PATH_SEGMENT } from './constants'; +import { + AUTHLESS_ENDPOINTS, + CURRENT_PACKAGE_VERSION, + PUBLIC_API_REST_PATH_SEGMENT, + REST_PATH_SEGMENT, +} from './constants'; import { AUTH_COOKIE_NAME, NODE_PACKAGE_PREFIX } from '../../../src/constants'; import { addRoutes as authMiddleware } from '../../../src/UserManagement/routes'; import { @@ -56,6 +61,7 @@ import type { N8nApp } from '../../../src/UserManagement/Interfaces'; import { workflowsController } from '../../../src/api/workflows.api'; import { nodesController } from '../../../src/api/nodes.api'; import { randomName } from './random'; +import { InstalledPackages } from '../../../src/databases/entities/InstalledPackages'; /** * Initialize a test server. @@ -101,7 +107,7 @@ export async function initTestServer({ credentials: { controller: credentialsController, path: 'credentials' }, workflows: { controller: workflowsController, path: 'workflows' }, nodes: { controller: nodesController, path: 'nodes' }, - publicApi: apiRouters + publicApi: apiRouters, }; for (const group of routerEndpoints) { @@ -139,6 +145,9 @@ export function initTestTelemetry() { void InternalHooksManager.init('test-instance-id', 'test-version', mockNodeTypes); } +export const createAuthAgent = (app: express.Application) => (user: User) => + createAgent(app, { auth: true, user }); + /** * Classify endpoint groups into `routerEndpoints` (newest, using `express.Router`), * and `functionEndpoints` (legacy, namespaced inside a function). @@ -893,7 +902,7 @@ export function getPostgresSchemaSection( } // ---------------------------------- -// nodes +// community nodes // ---------------------------------- export function installedPackagePayload(): InstalledPackagePayload { @@ -912,3 +921,11 @@ export function installedNodePayload(packageName: string): InstalledNodePayload package: packageName, }; } + +export const emptyPackage = () => { + const installedPackage = new InstalledPackages(); + installedPackage.installedNodes = []; + + return Promise.resolve(installedPackage); +}; + diff --git a/packages/cli/test/unit/CommunityNodeHelpers.test.ts b/packages/cli/test/unit/CommunityNodeHelpers.test.ts index e1324b6eea8..1724ae52934 100644 --- a/packages/cli/test/unit/CommunityNodeHelpers.test.ts +++ b/packages/cli/test/unit/CommunityNodeHelpers.test.ts @@ -1,330 +1,343 @@ -import { checkPackageStatus, matchPackagesWithUpdates, executeCommand, parsePackageName, matchMissingPackages, hasPackageLoadedSuccessfully, removePackageFromMissingList } from '../../src/CommunityNodes/helpers'; -import { NODE_PACKAGE_PREFIX, NPM_COMMAND_TOKENS, NPM_PACKAGE_STATUS_GOOD, RESPONSE_ERROR_MESSAGES } from '../../src/constants'; - -jest.mock('fs/promises'); +import { exec } from 'child_process'; import { access as fsAccess, mkdir as fsMkdir } from 'fs/promises'; -jest.mock('child_process'); -import { exec } from 'child_process'; -import { InstalledPackages } from '../../src/databases/entities/InstalledPackages'; -import { installedNodePayload, installedPackagePayload } from '../integration/shared/utils'; -import { InstalledNodes } from '../../src/databases/entities/InstalledNodes'; -import { NpmUpdatesAvailable } from '../../src/Interfaces'; -import { randomName } from '../integration/shared/random'; - -import config from '../../config'; - -jest.mock('axios'); import axios from 'axios'; -describe('CommunityNodesHelper', () => { +import { + checkNpmPackageStatus, + matchPackagesWithUpdates, + executeCommand, + parseNpmPackageName, + matchMissingPackages, + hasPackageLoaded, + removePackageFromMissingList, +} from '../../src/CommunityNodes/helpers'; +import { + NODE_PACKAGE_PREFIX, + NPM_COMMAND_TOKENS, + NPM_PACKAGE_STATUS_GOOD, + RESPONSE_ERROR_MESSAGES, +} from '../../src/constants'; +import { InstalledPackages } from '../../src/databases/entities/InstalledPackages'; +import { InstalledNodes } from '../../src/databases/entities/InstalledNodes'; +import { randomName } from '../integration/shared/random'; +import config from '../../config'; +import { installedPackagePayload, installedNodePayload } from '../integration/shared/utils'; - describe('parsePackageName', () => { - it('Should fail with empty package name', () => { - expect(() => parsePackageName('')).toThrowError() - }); +import type { CommunityPackages } from '../../src/Interfaces'; - it('Should fail with invalid package prefix name', () => { - expect(() => parsePackageName('INVALID_PREFIX@123')).toThrowError() - }); +jest.mock('fs/promises'); +jest.mock('child_process'); +jest.mock('axios'); - it('Should parse valid package name', () => { - const validPackageName = NODE_PACKAGE_PREFIX + 'cool-package-name'; - const parsedPackageName = parsePackageName(validPackageName); - - expect(parsedPackageName.originalString).toBe(validPackageName); - expect(parsedPackageName.packageName).toBe(validPackageName); - expect(parsedPackageName.scope).toBeUndefined(); - expect(parsedPackageName.version).toBeUndefined(); - }); - - it('Should parse valid package name and version', () => { - const validPackageName = NODE_PACKAGE_PREFIX + 'cool-package-name'; - const validPackageVersion = '0.1.1'; - const fullPackageName = `${validPackageName}@${validPackageVersion}`; - const parsedPackageName = parsePackageName(fullPackageName); - - expect(parsedPackageName.originalString).toBe(fullPackageName); - expect(parsedPackageName.packageName).toBe(validPackageName); - expect(parsedPackageName.scope).toBeUndefined(); - expect(parsedPackageName.version).toBe(validPackageVersion); - }); - - it('Should parse valid package name, scope and version', () => { - const validPackageScope = '@n8n'; - const validPackageName = NODE_PACKAGE_PREFIX + 'cool-package-name'; - const validPackageVersion = '0.1.1'; - const fullPackageName = `${validPackageScope}/${validPackageName}@${validPackageVersion}`; - const parsedPackageName = parsePackageName(fullPackageName); - - expect(parsedPackageName.originalString).toBe(fullPackageName); - expect(parsedPackageName.packageName).toBe(`${validPackageScope}/${validPackageName}`); - expect(parsedPackageName.scope).toBe(validPackageScope); - expect(parsedPackageName.version).toBe(validPackageVersion); - }); +describe('parsePackageName', () => { + test('Should fail with empty package name', () => { + expect(() => parseNpmPackageName('')).toThrowError(); }); - describe('executeCommand', () => { - - beforeEach(() => { - // @ts-ignore - fsAccess.mockReset(); - // @ts-ignore - fsMkdir.mockReset(); - // @ts-ignore - exec.mockReset(); - }); - - it('Should call command with valid options', async () => { - // @ts-ignore - exec.mockImplementation((...args) => { - expect(args[1].cwd).toBeDefined(); - expect(args[1].env).toBeDefined(); - // PATH or NODE_PATH may be undefined depending on environment so we don't check for these keys. - const callbackFunction = args[args.length - 1]; - callbackFunction(null, { stdout: 'Done' }); - }); - - await executeCommand('ls'); - expect(fsAccess).toHaveBeenCalled(); - expect(exec).toHaveBeenCalled(); - expect(fsMkdir).toBeCalledTimes(0); - }); - - it ('Should make sure folder exists', async () => { - // @ts-ignore - exec.mockImplementation((...args) => { - const callbackFunction = args[args.length - 1]; - callbackFunction(null, { stdout: 'Done' }); - }); - - await executeCommand('ls'); - expect(fsAccess).toHaveBeenCalled(); - expect(exec).toHaveBeenCalled(); - expect(fsMkdir).toBeCalledTimes(0); - }); - - it ('Should try to create folder if it does not exist', async () => { - // @ts-ignore - exec.mockImplementation((...args) => { - const callbackFunction = args[args.length - 1]; - callbackFunction(null, { stdout: 'Done' }); - }); - - // @ts-ignore - fsAccess.mockImplementation(() => { - throw new Error('Folder does not exist.'); - }); - - await executeCommand('ls'); - expect(fsAccess).toHaveBeenCalled(); - expect(exec).toHaveBeenCalled(); - expect(fsMkdir).toHaveBeenCalled(); - }); - - it('Should throw especial error when package is not found', async() => { - // @ts-ignore - exec.mockImplementation((...args) => { - const callbackFunction = args[args.length - 1]; - callbackFunction(new Error('Something went wrong - ' + NPM_COMMAND_TOKENS.NPM_PACKAGE_NOT_FOUND_ERROR + '. Aborting.')); - }); - - await expect(async () => await executeCommand('ls')).rejects.toThrow(RESPONSE_ERROR_MESSAGES.PACKAGE_NOT_FOUND); - - expect(fsAccess).toHaveBeenCalled(); - expect(exec).toHaveBeenCalled(); - expect(fsMkdir).toHaveBeenCalledTimes(0); - }); + test('Should fail with invalid package prefix name', () => { + expect(() => parseNpmPackageName('INVALID_PREFIX@123')).toThrowError(); }); + test('Should parse valid package name', () => { + const validPackageName = NODE_PACKAGE_PREFIX + 'cool-package-name'; + const parsed = parseNpmPackageName(validPackageName); - describe('crossInformationPackage', () => { - - it('Should return same list if availableUpdates is undefined', () => { - const fakePackages = generateListOfFakeInstalledPackages(); - const crossedData = matchPackagesWithUpdates(fakePackages); - expect(crossedData).toEqual(fakePackages); - }); - - it ('Should correctly match update versions for packages', () => { - const fakePackages = generateListOfFakeInstalledPackages(); - - const updates: NpmUpdatesAvailable = { - [fakePackages[0].packageName]: { - current: fakePackages[0].installedVersion, - wanted: fakePackages[0].installedVersion, - latest: '0.2.0', - location: fakePackages[0].packageName, - }, - [fakePackages[1].packageName]: { - current: fakePackages[0].installedVersion, - wanted: fakePackages[0].installedVersion, - latest: '0.3.0', - location: fakePackages[0].packageName, - } - }; - - const crossedData = matchPackagesWithUpdates(fakePackages, updates); - - // @ts-ignore - expect(crossedData[0].updateAvailable).toBe('0.2.0'); - // @ts-ignore - expect(crossedData[1].updateAvailable).toBe('0.3.0'); - - }); - - it ('Should correctly match update versions for single package', () => { - const fakePackages = generateListOfFakeInstalledPackages(); - - const updates: NpmUpdatesAvailable = { - [fakePackages[1].packageName]: { - current: fakePackages[0].installedVersion, - wanted: fakePackages[0].installedVersion, - latest: '0.3.0', - location: fakePackages[0].packageName, - } - }; - - const crossedData = matchPackagesWithUpdates(fakePackages, updates); - - // @ts-ignore - expect(crossedData[0].updateAvailable).toBeUndefined(); - // @ts-ignore - expect(crossedData[1].updateAvailable).toBe('0.3.0'); - - }); - + expect(parsed.rawString).toBe(validPackageName); + expect(parsed.packageName).toBe(validPackageName); + expect(parsed.scope).toBeUndefined(); + expect(parsed.version).toBeUndefined(); }); - describe('matchMissingPackages', () => { - it('Should not match failed packages that do not exist', () => { - const fakePackages = generateListOfFakeInstalledPackages(); - const notFoundPackageList = `${NODE_PACKAGE_PREFIX}very-long-name-that-should-never-be-generated@1.0.0 ${NODE_PACKAGE_PREFIX}another-very-long-name-that-never-is-seen`; - const matchedPackages = matchMissingPackages(fakePackages, notFoundPackageList); + test('Should parse valid package name and version', () => { + const validPackageName = NODE_PACKAGE_PREFIX + 'cool-package-name'; + const validPackageVersion = '0.1.1'; + const fullPackageName = `${validPackageName}@${validPackageVersion}`; + const parsed = parseNpmPackageName(fullPackageName); - expect(matchedPackages).toEqual(fakePackages); - expect(matchedPackages[0].failedLoading).toBeUndefined(); - expect(matchedPackages[1].failedLoading).toBeUndefined(); - }); - - it('Should match failed packages that should be present', () => { - const fakePackages = generateListOfFakeInstalledPackages(); - const notFoundPackageList = `${NODE_PACKAGE_PREFIX}very-long-name-that-should-never-be-generated@1.0.0 ${fakePackages[0].packageName}@${fakePackages[0].installedVersion}`; - const matchedPackages = matchMissingPackages(fakePackages, notFoundPackageList); - - expect(matchedPackages[0].failedLoading).toBe(true); - expect(matchedPackages[1].failedLoading).toBeUndefined(); - }); - - it('Should match failed packages even if version is wrong', () => { - const fakePackages = generateListOfFakeInstalledPackages(); - const notFoundPackageList = `${NODE_PACKAGE_PREFIX}very-long-name-that-should-never-be-generated@1.0.0 ${fakePackages[0].packageName}@123.456.789`; - const matchedPackages = matchMissingPackages(fakePackages, notFoundPackageList); - - expect(matchedPackages[0].failedLoading).toBe(true); - expect(matchedPackages[1].failedLoading).toBeUndefined(); - }); + expect(parsed.rawString).toBe(fullPackageName); + expect(parsed.packageName).toBe(validPackageName); + expect(parsed.scope).toBeUndefined(); + expect(parsed.version).toBe(validPackageVersion); }); - describe('checkPackageStatus', () => { - it('Should call axios.post', async () => { - const packageName = NODE_PACKAGE_PREFIX + randomName(); - await checkPackageStatus(packageName); - expect(axios.post).toHaveBeenCalled(); - }); + test('Should parse valid package name, scope and version', () => { + const validPackageScope = '@n8n'; + const validPackageName = NODE_PACKAGE_PREFIX + 'cool-package-name'; + const validPackageVersion = '0.1.1'; + const fullPackageName = `${validPackageScope}/${validPackageName}@${validPackageVersion}`; + const parsed = parseNpmPackageName(fullPackageName); - it('Should not fail if request fails', async () => { - const packageName = NODE_PACKAGE_PREFIX + randomName(); - axios.post = jest.fn(() => { - throw new Error('Something went wrong'); - }); - const result = await checkPackageStatus(packageName); - expect(result.status).toBe(NPM_PACKAGE_STATUS_GOOD); - }); + expect(parsed.rawString).toBe(fullPackageName); + expect(parsed.packageName).toBe(`${validPackageScope}/${validPackageName}`); + expect(parsed.scope).toBe(validPackageScope); + expect(parsed.version).toBe(validPackageVersion); + }); +}); - it('Should warn if package is banned', async () => { - const packageName = NODE_PACKAGE_PREFIX + randomName(); - // @ts-ignore - axios.post = jest.fn(() => { - return { data: { status: 'Banned', reason: 'Not good' } }; - }); - const result = await checkPackageStatus(packageName); - expect(result.status).toBe('Banned'); - expect(result.reason).toBe('Not good'); - }); +describe('executeCommand', () => { + beforeEach(() => { + // @ts-ignore + fsAccess.mockReset(); + // @ts-ignore + fsMkdir.mockReset(); + // @ts-ignore + exec.mockReset(); }); - describe('hasPackageLoadedSuccessfully', () => { - it('Should return true when failed package list does not exist', () => { - config.set('nodes.packagesMissing', undefined); - const result = hasPackageLoadedSuccessfully('package'); - expect(result).toBe(true); + test('Should call command with valid options', async () => { + // @ts-ignore + exec.mockImplementation((...args) => { + expect(args[1].cwd).toBeDefined(); + expect(args[1].env).toBeDefined(); + // PATH or NODE_PATH may be undefined depending on environment so we don't check for these keys. + const callbackFunction = args[args.length - 1]; + callbackFunction(null, { stdout: 'Done' }); }); - it('Should return true when package is not in the list of missing packages', () => { - config.set('nodes.packagesMissing', 'packageA@0.1.0 packgeB@0.1.0'); - const result = hasPackageLoadedSuccessfully('packageC'); - expect(result).toBe(true); - }); - - it('Should return false when package is in the list of missing packages', () => { - config.set('nodes.packagesMissing', 'packageA@0.1.0 packgeB@0.1.0'); - const result = hasPackageLoadedSuccessfully('packageA'); - expect(result).toBe(false); - }); + await executeCommand('ls'); + expect(fsAccess).toHaveBeenCalled(); + expect(exec).toHaveBeenCalled(); + expect(fsMkdir).toBeCalledTimes(0); }); - describe('removePackageFromMissingList', () => { - it('Should do nothing if key does not exist', () => { - config.set('nodes.packagesMissing', undefined); - - removePackageFromMissingList('packageA'); - - const packageList = config.get('nodes.packagesMissing'); - expect(packageList).toBeUndefined(); + test('Should make sure folder exists', async () => { + // @ts-ignore + exec.mockImplementation((...args) => { + const callbackFunction = args[args.length - 1]; + callbackFunction(null, { stdout: 'Done' }); }); - it('Should remove only correct package from list', () => { - config.set('nodes.packagesMissing', 'packageA@0.1.0 packageB@0.2.0 packageBB@0.2.0'); + await executeCommand('ls'); + expect(fsAccess).toHaveBeenCalled(); + expect(exec).toHaveBeenCalled(); + expect(fsMkdir).toBeCalledTimes(0); + }); - removePackageFromMissingList('packageB'); - - const packageList = config.get('nodes.packagesMissing'); - expect(packageList).toBe('packageA@0.1.0 packageBB@0.2.0'); + test('Should try to create folder if it does not exist', async () => { + // @ts-ignore + exec.mockImplementation((...args) => { + const callbackFunction = args[args.length - 1]; + callbackFunction(null, { stdout: 'Done' }); }); - - it('Should not remove if package is not in the list', () => { - const failedToLoadList = 'packageA@0.1.0 packageB@0.2.0 packageBB@0.2.0'; - config.set('nodes.packagesMissing', failedToLoadList); - - removePackageFromMissingList('packageC'); - - const packageList = config.get('nodes.packagesMissing'); - expect(packageList).toBe(failedToLoadList); + // @ts-ignore + fsAccess.mockImplementation(() => { + throw new Error('Folder does not exist.'); }); + await executeCommand('ls'); + expect(fsAccess).toHaveBeenCalled(); + expect(exec).toHaveBeenCalled(); + expect(fsMkdir).toHaveBeenCalled(); + }); + + test('Should throw especial error when package is not found', async () => { + // @ts-ignore + exec.mockImplementation((...args) => { + const callbackFunction = args[args.length - 1]; + callbackFunction( + new Error( + 'Something went wrong - ' + + NPM_COMMAND_TOKENS.NPM_PACKAGE_NOT_FOUND_ERROR + + '. Aborting.', + ), + ); + }); + + await expect(async () => await executeCommand('ls')).rejects.toThrow( + RESPONSE_ERROR_MESSAGES.PACKAGE_NOT_FOUND, + ); + + expect(fsAccess).toHaveBeenCalled(); + expect(exec).toHaveBeenCalled(); + expect(fsMkdir).toHaveBeenCalledTimes(0); + }); +}); + +describe('crossInformationPackage', () => { + test('Should return same list if availableUpdates is undefined', () => { + const fakePackages = generateListOfFakeInstalledPackages(); + const crossedData = matchPackagesWithUpdates(fakePackages); + expect(crossedData).toEqual(fakePackages); + }); + + test('Should correctly match update versions for packages', () => { + const fakePackages = generateListOfFakeInstalledPackages(); + + const updates: CommunityPackages.AvailableUpdates = { + [fakePackages[0].packageName]: { + current: fakePackages[0].installedVersion, + wanted: fakePackages[0].installedVersion, + latest: '0.2.0', + location: fakePackages[0].packageName, + }, + [fakePackages[1].packageName]: { + current: fakePackages[0].installedVersion, + wanted: fakePackages[0].installedVersion, + latest: '0.3.0', + location: fakePackages[0].packageName, + }, + }; + + const crossedData = matchPackagesWithUpdates(fakePackages, updates); + + // @ts-ignore + expect(crossedData[0].updateAvailable).toBe('0.2.0'); + // @ts-ignore + expect(crossedData[1].updateAvailable).toBe('0.3.0'); + }); + + test('Should correctly match update versions for single package', () => { + const fakePackages = generateListOfFakeInstalledPackages(); + + const updates: CommunityPackages.AvailableUpdates = { + [fakePackages[1].packageName]: { + current: fakePackages[0].installedVersion, + wanted: fakePackages[0].installedVersion, + latest: '0.3.0', + location: fakePackages[0].packageName, + }, + }; + + const crossedData = matchPackagesWithUpdates(fakePackages, updates); + + // @ts-ignore + expect(crossedData[0].updateAvailable).toBeUndefined(); + // @ts-ignore + expect(crossedData[1].updateAvailable).toBe('0.3.0'); + }); +}); + +describe('matchMissingPackages', () => { + test('Should not match failed packages that do not exist', () => { + const fakePackages = generateListOfFakeInstalledPackages(); + const notFoundPackageList = `${NODE_PACKAGE_PREFIX}very-long-name-that-should-never-be-generated@1.0.0 ${NODE_PACKAGE_PREFIX}another-very-long-name-that-never-is-seen`; + const matchedPackages = matchMissingPackages(fakePackages, notFoundPackageList); + + expect(matchedPackages).toEqual(fakePackages); + expect(matchedPackages[0].failedLoading).toBeUndefined(); + expect(matchedPackages[1].failedLoading).toBeUndefined(); + }); + + test('Should match failed packages that should be present', () => { + const fakePackages = generateListOfFakeInstalledPackages(); + const notFoundPackageList = `${NODE_PACKAGE_PREFIX}very-long-name-that-should-never-be-generated@1.0.0 ${fakePackages[0].packageName}@${fakePackages[0].installedVersion}`; + const matchedPackages = matchMissingPackages(fakePackages, notFoundPackageList); + + expect(matchedPackages[0].failedLoading).toBe(true); + expect(matchedPackages[1].failedLoading).toBeUndefined(); + }); + + test('Should match failed packages even if version is wrong', () => { + const fakePackages = generateListOfFakeInstalledPackages(); + const notFoundPackageList = `${NODE_PACKAGE_PREFIX}very-long-name-that-should-never-be-generated@1.0.0 ${fakePackages[0].packageName}@123.456.789`; + const matchedPackages = matchMissingPackages(fakePackages, notFoundPackageList); + + expect(matchedPackages[0].failedLoading).toBe(true); + expect(matchedPackages[1].failedLoading).toBeUndefined(); + }); +}); + +describe('checkNpmPackageStatus', () => { + test('Should call axios.post', async () => { + const packageName = NODE_PACKAGE_PREFIX + randomName(); + await checkNpmPackageStatus(packageName); + expect(axios.post).toHaveBeenCalled(); + }); + + test('Should not fail if request fails', async () => { + const packageName = NODE_PACKAGE_PREFIX + randomName(); + axios.post = jest.fn(() => { + throw new Error('Something went wrong'); + }); + const result = await checkNpmPackageStatus(packageName); + expect(result.status).toBe(NPM_PACKAGE_STATUS_GOOD); + }); + + test('Should warn if package is banned', async () => { + const packageName = NODE_PACKAGE_PREFIX + randomName(); + // @ts-ignore + axios.post = jest.fn(() => { + return { data: { status: 'Banned', reason: 'Not good' } }; + }); + const result = await checkNpmPackageStatus(packageName); + expect(result.status).toBe('Banned'); + expect(result.reason).toBe('Not good'); + }); +}); + +describe('hasPackageLoadedSuccessfully', () => { + test('Should return true when failed package list does not exist', () => { + config.set('nodes.packagesMissing', undefined); + const result = hasPackageLoaded('package'); + expect(result).toBe(true); + }); + + test('Should return true when package is not in the list of missing packages', () => { + config.set('nodes.packagesMissing', 'packageA@0.1.0 packgeB@0.1.0'); + const result = hasPackageLoaded('packageC'); + expect(result).toBe(true); + }); + + test('Should return false when package is in the list of missing packages', () => { + config.set('nodes.packagesMissing', 'packageA@0.1.0 packgeB@0.1.0'); + const result = hasPackageLoaded('packageA'); + expect(result).toBe(false); + }); +}); + +describe('removePackageFromMissingList', () => { + test('Should do nothing if key does not exist', () => { + config.set('nodes.packagesMissing', undefined); + + removePackageFromMissingList('packageA'); + + const packageList = config.get('nodes.packagesMissing'); + expect(packageList).toBeUndefined(); + }); + + test('Should remove only correct package from list', () => { + config.set('nodes.packagesMissing', 'packageA@0.1.0 packageB@0.2.0 packageBB@0.2.0'); + + removePackageFromMissingList('packageB'); + + const packageList = config.get('nodes.packagesMissing'); + expect(packageList).toBe('packageA@0.1.0 packageBB@0.2.0'); + }); + + test('Should not remove if package is not in the list', () => { + const failedToLoadList = 'packageA@0.1.0 packageB@0.2.0 packageBB@0.2.0'; + config.set('nodes.packagesMissing', failedToLoadList); + + removePackageFromMissingList('packageC'); + + const packageList = config.get('nodes.packagesMissing'); + expect(packageList).toBe(failedToLoadList); }); }); /** - * Generates a list with 2 packages, one with a single node and - * another with 2 nodes - * @returns + * Generate a list with 2 packages, one with a single node and another with 2 nodes */ function generateListOfFakeInstalledPackages(): InstalledPackages[] { const fakeInstalledPackage1 = new InstalledPackages(); Object.assign(fakeInstalledPackage1, installedPackagePayload()); + const fakeInstalledNode1 = new InstalledNodes(); Object.assign(fakeInstalledNode1, installedNodePayload(fakeInstalledPackage1.packageName)); + fakeInstalledPackage1.installedNodes = [fakeInstalledNode1]; const fakeInstalledPackage2 = new InstalledPackages(); Object.assign(fakeInstalledPackage2, installedPackagePayload()); + const fakeInstalledNode2 = new InstalledNodes(); Object.assign(fakeInstalledNode2, installedNodePayload(fakeInstalledPackage2.packageName)); + const fakeInstalledNode3 = new InstalledNodes(); Object.assign(fakeInstalledNode3, installedNodePayload(fakeInstalledPackage2.packageName)); + fakeInstalledPackage2.installedNodes = [fakeInstalledNode2, fakeInstalledNode3]; return [fakeInstalledPackage1, fakeInstalledPackage2]; From 2cab8e7779c82a7a9f83d7ef0a08f51b5810a5ce Mon Sep 17 00:00:00 2001 From: brianinoa <54530642+brianinoa@users.noreply.github.com> Date: Tue, 2 Aug 2022 16:43:31 +0200 Subject: [PATCH 084/609] refactor(core): Remove request libraries from cli package (#3803) * :heavy_minus_sign: Remove request libraries * :recycle: Refactor requests and remove unused imports * :zap: Fix loaded workflow gets parsed twice * :zap: Fix remote workflow is parsed twice as json * :zap: Fix workflowData assignment when data is fetched * :zap: Fix move workflow request and assignment into try/catch block --- packages/cli/package.json | 2 -- packages/cli/src/Server.ts | 39 +++++++++++++++++--------------------- 2 files changed, 17 insertions(+), 24 deletions(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index 206c91c83eb..d5ffbeddfc7 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -81,7 +81,6 @@ "@types/parseurl": "^1.3.1", "@types/passport-jwt": "^3.0.6", "@types/psl": "^1.1.0", - "@types/request-promise-native": "~1.0.15", "@types/superagent": "4.1.13", "@types/supertest": "^2.0.11", "@types/uuid": "^8.3.2", @@ -159,7 +158,6 @@ "pg": "^8.3.0", "prom-client": "^13.1.0", "psl": "^1.8.0", - "request-promise-native": "^1.0.7", "shelljs": "^0.8.5", "sqlite3": "^5.0.2", "sse-channel": "^3.1.1", diff --git a/packages/cli/src/Server.ts b/packages/cli/src/Server.ts index f0830e9280b..9a18f5d132d 100644 --- a/packages/cli/src/Server.ts +++ b/packages/cli/src/Server.ts @@ -37,7 +37,6 @@ import _, { cloneDeep } from 'lodash'; import { dirname as pathDirname, join as pathJoin, resolve as pathResolve } from 'path'; import { FindManyOptions, - getConnection, getConnectionManager, In, IsNull, @@ -50,10 +49,8 @@ import cookieParser from 'cookie-parser'; import history from 'connect-history-api-fallback'; import os from 'os'; // eslint-disable-next-line import/no-extraneous-dependencies -import clientOAuth2 from 'client-oauth2'; import clientOAuth1, { RequestOptions } from 'oauth-1.0a'; -import csrf from 'csrf'; -import requestPromise, { OptionsWithUrl } from 'request-promise-native'; +import axios, { AxiosRequestConfig, AxiosPromise } from 'axios'; import { createHmac, randomBytes } from 'crypto'; // IMPORTANT! Do not switch to anther bcrypt library unless really necessary and // tested with all possible systems like Windows, Alpine on ARM, FreeBSD, ... @@ -88,11 +85,9 @@ import jwks from 'jwks-rsa'; // @ts-ignore import timezones from 'google-timezones-json'; import parseUrl from 'parseurl'; -import querystring from 'querystring'; import promClient, { Registry } from 'prom-client'; import * as Queue from './Queue'; import { - LoadNodesAndCredentials, ActiveExecutions, ActiveWorkflowRunner, CredentialsHelper, @@ -150,8 +145,6 @@ import { userManagementRouter } from './UserManagement'; import { resolveJwt } from './UserManagement/auth/jwt'; import { User } from './databases/entities/User'; import type { - AuthenticatedRequest, - CredentialRequest, ExecutionRequest, NodeParameterOptionsRequest, OAuthRequest, @@ -171,7 +164,6 @@ import { isUserManagementEnabled, } from './UserManagement/UserManagementHelper'; import { loadPublicApiVersions } from './PublicApi'; -import { SharedWorkflow } from './databases/entities/SharedWorkflow'; require('body-parser-xml')(bodyParser); @@ -793,11 +785,10 @@ class App { 400, ); } - const data = await requestPromise.get(req.query.url as string); - let workflowData: IWorkflowResponse | undefined; try { - workflowData = JSON.parse(data); + const { data } = await axios.get(req.query.url as string); + workflowData = data; } catch (error) { throw new ResponseHelper.ResponseError( `The URL does not point to valid JSON file!`, @@ -1714,11 +1705,13 @@ class App { // @ts-ignore options.headers = data; - const response = await requestPromise(options); + const { data: response } = await axios.request(options as Partial); // Response comes as x-www-form-urlencoded string so convert it to JSON - const responseJson = querystring.parse(response); + const paramsParser = new URLSearchParams(response); + + const responseJson = Object.fromEntries(paramsParser.entries()); const returnUri = `${_.get(oauthCredentials, 'authUrl')}?oauth_token=${ responseJson.oauth_token @@ -1813,10 +1806,10 @@ class App { timezone, ); - const options: OptionsWithUrl = { + const options: AxiosRequestConfig = { method: 'POST', url: _.get(oauthCredentials, 'accessTokenUrl') as string, - qs: { + params: { oauth_token, oauth_verifier, }, @@ -1825,7 +1818,7 @@ class App { let oauthToken; try { - oauthToken = await requestPromise(options); + oauthToken = await axios.request(options); } catch (error) { LoggerProxy.error('Unable to fetch tokens for OAuth1 callback', { userId: req.user?.id, @@ -1841,7 +1834,9 @@ class App { // Response comes as x-www-form-urlencoded string so convert it to JSON - const oauthTokenJson = querystring.parse(oauthToken); + const paramParser = new URLSearchParams(oauthToken.data); + + const oauthTokenJson = Object.fromEntries(paramParser.entries()); decryptedDataOriginal.oauthTokenData = oauthTokenJson; @@ -1940,7 +1935,7 @@ class App { filterToAdd = { [key]: value }; } - Object.assign(findOptions.where, filterToAdd); + Object.assign(findOptions.where!, filterToAdd); }); const rangeQuery: string[] = []; @@ -1966,7 +1961,7 @@ class App { } if (rangeQuery.length) { - Object.assign(findOptions.where, { + Object.assign(findOptions.where!, { id: Raw(() => rangeQuery.join(' and '), rangeQueryParams), }); } @@ -2288,10 +2283,10 @@ class App { if (req.query.filter) { const { workflowId } = JSON.parse(req.query.filter); if (workflowId && sharedWorkflowIds.includes(workflowId)) { - Object.assign(findOptions.where, { workflowId }); + Object.assign(findOptions.where!, { workflowId }); } } else { - Object.assign(findOptions.where, { workflowId: In(sharedWorkflowIds) }); + Object.assign(findOptions.where!, { workflowId: In(sharedWorkflowIds) }); } const executions = await Db.collections.Execution.find(findOptions); From f0dddaa2a585715b35e26b16e1003e1683ab9402 Mon Sep 17 00:00:00 2001 From: brianinoa <54530642+brianinoa@users.noreply.github.com> Date: Tue, 2 Aug 2022 17:18:57 +0200 Subject: [PATCH 085/609] fix: Fix problem saving workflow when tags disabled (#3792) * :zap: Add @AfterLoad nullCheck for WorkflowEntity tags * :zap: Make tags optional in Entity * Fix workflows api typing issue Co-authored-by: Omar Ajoue --- packages/cli/src/Interfaces.ts | 2 +- packages/cli/src/Server.ts | 2 +- packages/cli/src/api/workflows.api.ts | 2 +- packages/cli/src/databases/entities/WorkflowEntity.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/cli/src/Interfaces.ts b/packages/cli/src/Interfaces.ts index aa4150c7ffb..64f7c0a473a 100644 --- a/packages/cli/src/Interfaces.ts +++ b/packages/cli/src/Interfaces.ts @@ -144,7 +144,7 @@ export interface IWorkflowBase extends IWorkflowBaseWorkflow { // Almost identical to editor-ui.Interfaces.ts export interface IWorkflowDb extends IWorkflowBase { id: number | string; - tags: ITagDb[]; + tags?: ITagDb[]; } export interface IWorkflowToImport extends IWorkflowBase { diff --git a/packages/cli/src/Server.ts b/packages/cli/src/Server.ts index 9a18f5d132d..b9698f44f19 100644 --- a/packages/cli/src/Server.ts +++ b/packages/cli/src/Server.ts @@ -993,7 +993,7 @@ class App { ); } - if (updatedWorkflow.tags.length && tags?.length) { + if (updatedWorkflow.tags?.length && tags?.length) { updatedWorkflow.tags = TagHelpers.sortByRequestOrder(updatedWorkflow.tags, { requestOrder: tags, }); diff --git a/packages/cli/src/api/workflows.api.ts b/packages/cli/src/api/workflows.api.ts index 3afd63f8b7f..076715751da 100644 --- a/packages/cli/src/api/workflows.api.ts +++ b/packages/cli/src/api/workflows.api.ts @@ -69,7 +69,7 @@ workflowsController.post( throw new ResponseHelper.ResponseError('Failed to save workflow'); } - if (tagIds && !config.getEnv('workflowTagsDisabled')) { + if (tagIds && !config.getEnv('workflowTagsDisabled') && savedWorkflow.tags) { savedWorkflow.tags = TagHelpers.sortByRequestOrder(savedWorkflow.tags, { requestOrder: tagIds, }); diff --git a/packages/cli/src/databases/entities/WorkflowEntity.ts b/packages/cli/src/databases/entities/WorkflowEntity.ts index b3e0427ee2d..94a1183a9df 100644 --- a/packages/cli/src/databases/entities/WorkflowEntity.ts +++ b/packages/cli/src/databases/entities/WorkflowEntity.ts @@ -112,7 +112,7 @@ export class WorkflowEntity implements IWorkflowDb { referencedColumnName: 'id', }, }) - tags: TagEntity[]; + tags?: TagEntity[]; @OneToMany(() => SharedWorkflow, (sharedWorkflow) => sharedWorkflow.workflow) shared: SharedWorkflow[]; From 0f27be4447662056a2ba13c027280830f7eab09b Mon Sep 17 00:00:00 2001 From: Mutasem Aldmour <4711238+mutdmour@users.noreply.github.com> Date: Tue, 2 Aug 2022 17:21:21 +0200 Subject: [PATCH 086/609] fix(editor): Fix label cut off (#3820) --- .../src/components/N8nInputLabel/InputLabel.vue | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/design-system/src/components/N8nInputLabel/InputLabel.vue b/packages/design-system/src/components/N8nInputLabel/InputLabel.vue index 59b67c82965..66eccd4195a 100644 --- a/packages/design-system/src/components/N8nInputLabel/InputLabel.vue +++ b/packages/design-system/src/components/N8nInputLabel/InputLabel.vue @@ -1,12 +1,13 @@ @@ -156,24 +136,23 @@ \ No newline at end of file diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index 668d4c891d9..f2db52bec00 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -362,6 +362,7 @@ "dist/nodes/Aws/AwsSnsTrigger.node.js", "dist/nodes/Aws/Comprehend/AwsComprehend.node.js", "dist/nodes/Aws/DynamoDB/AwsDynamoDB.node.js", + "dist/nodes/Aws/ELB/AwsElb.node.js", "dist/nodes/Aws/Rekognition/AwsRekognition.node.js", "dist/nodes/Aws/S3/AwsS3.node.js", "dist/nodes/Aws/SES/AwsSes.node.js", From 9b3f30d584901e7dc5fa87854e72f438f2557665 Mon Sep 17 00:00:00 2001 From: Ricardo Espinoza Date: Fri, 7 Oct 2022 09:08:55 -0400 Subject: [PATCH 548/609] feat(AWS Certificate Manager): add AWS Certificate Manager node (#4263) * :sparkles: AWS Certificate Manager * :zap: Add codex and paired items * :zap: Add codex * :bug: Fix typo --- .../AwsCertificateManager.node.json | 29 ++ .../AwsCertificateManager.node.ts | 231 +++++++++++++ .../CertificateDescription.ts | 327 ++++++++++++++++++ .../CertificateManager/GenericFunctions.ts | 96 +++++ .../nodes/Aws/CertificateManager/acm.svg | 1 + packages/nodes-base/package.json | 1 + 6 files changed, 685 insertions(+) create mode 100644 packages/nodes-base/nodes/Aws/CertificateManager/AwsCertificateManager.node.json create mode 100644 packages/nodes-base/nodes/Aws/CertificateManager/AwsCertificateManager.node.ts create mode 100644 packages/nodes-base/nodes/Aws/CertificateManager/CertificateDescription.ts create mode 100644 packages/nodes-base/nodes/Aws/CertificateManager/GenericFunctions.ts create mode 100644 packages/nodes-base/nodes/Aws/CertificateManager/acm.svg diff --git a/packages/nodes-base/nodes/Aws/CertificateManager/AwsCertificateManager.node.json b/packages/nodes-base/nodes/Aws/CertificateManager/AwsCertificateManager.node.json new file mode 100644 index 00000000000..f1bc023d8e6 --- /dev/null +++ b/packages/nodes-base/nodes/Aws/CertificateManager/AwsCertificateManager.node.json @@ -0,0 +1,29 @@ +{ + "node": "n8n-nodes-base.awsCertificateManager", + "nodeVersion": "1.0", + "codexVersion": "1.0", + "categories": ["Development"], + "resources": { + "credentialDocumentation": [ + { + "url": "https://docs.n8n.io/credentials/aws" + } + ], + "primaryDocumentation": [ + { + "url": "https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.awsCertificateManager/" + } + ], + "generic": [ + { + "label": "Why business process automation with n8n can change your daily life", + "icon": "🧬", + "url": "https://n8n.io/blog/why-business-process-automation-with-n8n-can-change-your-daily-life/" + }, + { + "label": "7 no-code workflow automations for Amazon Web Services", + "url": "https://n8n.io/blog/aws-workflow-automation/" + } + ] + } +} diff --git a/packages/nodes-base/nodes/Aws/CertificateManager/AwsCertificateManager.node.ts b/packages/nodes-base/nodes/Aws/CertificateManager/AwsCertificateManager.node.ts new file mode 100644 index 00000000000..3039268da3a --- /dev/null +++ b/packages/nodes-base/nodes/Aws/CertificateManager/AwsCertificateManager.node.ts @@ -0,0 +1,231 @@ +import { IExecuteFunctions } from 'n8n-core'; + +import { IDataObject, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow'; + +import { certificateFields, certificateOperations } from './CertificateDescription'; + +import { awsApiRequestAllItems, awsApiRequestREST } from './GenericFunctions'; + +export class AwsCertificateManager implements INodeType { + description: INodeTypeDescription = { + displayName: 'AWS Certificate Manager', + name: 'awsCertificateManager', + icon: 'file:acm.svg', + group: ['output'], + version: 1, + subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', + description: 'Sends data to AWS Certificate Manager', + defaults: { + name: 'AWS Certificate Manager', + color: '#7d9a4b', + }, + inputs: ['main'], + outputs: ['main'], + credentials: [ + { + name: 'aws', + required: true, + }, + ], + properties: [ + { + displayName: 'Resource', + name: 'resource', + type: 'options', + noDataExpression: true, + options: [ + { + name: 'Certificate', + value: 'certificate', + }, + ], + default: 'certificate', + }, + // Certificate + ...certificateOperations, + ...certificateFields, + ], + }; + + async execute(this: IExecuteFunctions): Promise { + const items = this.getInputData(); + const returnData: IDataObject[] = []; + const qs: IDataObject = {}; + let responseData; + const resource = this.getNodeParameter('resource', 0) as string; + const operation = this.getNodeParameter('operation', 0) as string; + for (let i = 0; i < items.length; i++) { + try { + if (resource === 'certificate') { + //https://docs.aws.amazon.com/acm/latest/APIReference/API_DeleteCertificate.html + if (operation === 'delete') { + const certificateArn = this.getNodeParameter('certificateArn', i) as string; + + const body: IDataObject = { + CertificateArn: certificateArn, + }; + + responseData = await awsApiRequestREST.call( + this, + `acm`, + 'POST', + '', + JSON.stringify(body), + qs, + { + 'X-Amz-Target': 'CertificateManager.DeleteCertificate', + 'Content-Type': 'application/x-amz-json-1.1', + }, + ); + + responseData = { success: true }; + } + + //https://docs.aws.amazon.com/acm/latest/APIReference/API_GetCertificate.html + if (operation === 'get') { + const certificateArn = this.getNodeParameter('certificateArn', i) as string; + + const body: IDataObject = { + CertificateArn: certificateArn, + }; + + responseData = await awsApiRequestREST.call( + this, + `acm`, + 'POST', + '', + JSON.stringify(body), + qs, + { + 'X-Amz-Target': 'CertificateManager.GetCertificate', + 'Content-Type': 'application/x-amz-json-1.1', + }, + ); + } + + //https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectsV2.html + if (operation === 'getMany') { + const returnAll = this.getNodeParameter('returnAll', 0) as boolean; + const options = this.getNodeParameter('options', i) as IDataObject; + + const body: { Includes: IDataObject; CertificateStatuses: string[]; MaxItems: number } = { + CertificateStatuses: [], + Includes: {}, + MaxItems: 0, + }; + + if (options.certificateStatuses) { + body.CertificateStatuses = options.certificateStatuses as string[]; + } + + if (options.certificateStatuses) { + body.Includes['extendedKeyUsage'] = options.extendedKeyUsage as string[]; + } + + if (options.keyTypes) { + body.Includes['keyTypes'] = options.keyTypes as string[]; + } + + if (options.keyUsage) { + body.Includes['keyUsage'] = options.keyUsage as string[]; + } + + if (returnAll) { + responseData = await awsApiRequestAllItems.call( + this, + 'CertificateSummaryList', + 'acm', + 'POST', + '', + '{}', + qs, + { + 'X-Amz-Target': 'CertificateManager.ListCertificates', + 'Content-Type': 'application/x-amz-json-1.1', + }, + ); + } else { + body.MaxItems = this.getNodeParameter('limit', 0) as number; + responseData = await awsApiRequestREST.call( + this, + `acm`, + 'POST', + '', + JSON.stringify(body), + qs, + { + 'X-Amz-Target': 'CertificateManager.ListCertificates', + 'Content-Type': 'application/x-amz-json-1.1', + }, + ); + responseData = responseData.CertificateSummaryList; + } + } + + //https://docs.aws.amazon.com/acm/latest/APIReference/API_DescribeCertificate.html + if (operation === 'getMetadata') { + const certificateArn = this.getNodeParameter('certificateArn', i) as string; + + const body: IDataObject = { + CertificateArn: certificateArn, + }; + + responseData = await awsApiRequestREST.call( + this, + `acm`, + 'POST', + '', + JSON.stringify(body), + qs, + { + 'X-Amz-Target': 'CertificateManager.DescribeCertificate', + 'Content-Type': 'application/x-amz-json-1.1', + }, + ); + + responseData = responseData.Certificate; + } + + //https://docs.aws.amazon.com/acm/latest/APIReference/API_RenewCertificate.html + if (operation === 'renew') { + const certificateArn = this.getNodeParameter('certificateArn', i) as string; + + const body: IDataObject = { + CertificateArn: certificateArn, + }; + + responseData = await awsApiRequestREST.call( + this, + `acm`, + 'POST', + '', + JSON.stringify(body), + qs, + { + 'X-Amz-Target': 'CertificateManager.RenewCertificate', + 'Content-Type': 'application/x-amz-json-1.1', + }, + ); + + responseData = { success: true }; + } + + const executionData = this.helpers.constructExecutionMetaData( + this.helpers.returnJsonArray(responseData), + { itemData: { item: i } }, + ); + + returnData.push(...executionData); + } + } catch (error) { + if (this.continueOnFail()) { + returnData.push({ json: { error: error.message } }); + continue; + } + throw error; + } + } + + return [returnData as INodeExecutionData[]]; + } +} diff --git a/packages/nodes-base/nodes/Aws/CertificateManager/CertificateDescription.ts b/packages/nodes-base/nodes/Aws/CertificateManager/CertificateDescription.ts new file mode 100644 index 00000000000..7b3a8b0097e --- /dev/null +++ b/packages/nodes-base/nodes/Aws/CertificateManager/CertificateDescription.ts @@ -0,0 +1,327 @@ +import { INodeProperties } from 'n8n-workflow'; + +export const certificateOperations: INodeProperties[] = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + noDataExpression: true, + displayOptions: { + show: { + resource: ['certificate'], + }, + }, + options: [ + { + name: 'Delete', + value: 'delete', + description: 'Delete a certificate', + action: 'Delete a certificate', + }, + { + name: 'Get', + value: 'get', + description: 'Get a certificate', + action: 'Get a certificate', + }, + { + name: 'Get Many', + value: 'getMany', + description: 'Get many certificates', + action: 'Get many certificates', + }, + { + name: 'Get Metadata', + value: 'getMetadata', + description: 'Get certificate metadata', + action: 'Get certificate metadata', + }, + { + name: 'Renew', + value: 'renew', + description: 'Renew a certificate', + action: 'Renew a certificate', + }, + ], + default: 'renew', + }, +]; + +export const certificateFields: INodeProperties[] = [ + /* -------------------------------------------------------------------------- */ + /* certificate:renew */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Certificate ARN', + name: 'certificateArn', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: ['certificate'], + operation: ['renew', 'get', 'delete', 'getMetadata'], + }, + }, + description: + 'String that contains the ARN of the ACM certificate to be renewed. This must be of the form: arn:aws:acm:region:123456789012:certificate/12345678-1234-1234-1234-123456789012.', + }, + /* -------------------------------------------------------------------------- */ + /* certificate:delete */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Bucket Name', + name: 'bucketName', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: ['certificate'], + operation: ['delete'], + }, + }, + }, + { + displayName: 'Certificate Key', + name: 'certificateKey', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: ['certificate'], + operation: ['delete'], + }, + }, + }, + /* -------------------------------------------------------------------------- */ + /* certificate:getMany */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + operation: ['getMany'], + resource: ['certificate'], + }, + }, + default: false, + description: 'Whether to return all results or only up to a given limit', + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + displayOptions: { + show: { + operation: ['getMany'], + resource: ['certificate'], + returnAll: [false], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 500, + }, + default: 100, + description: 'Max number of results to return', + }, + { + displayName: 'Options', + name: 'options', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: ['certificate'], + operation: ['getMany'], + }, + }, + options: [ + { + displayName: 'Certificate Statuses', + name: 'certificateStatuses', + type: 'multiOptions', + options: [ + { + name: 'Expired', + value: 'EXPIRED', + }, + { + name: 'Failed', + value: 'FAILED', + }, + { + name: 'Inactive', + value: 'INACTIVE', + }, + { + name: 'Issued', + value: 'ISSUED', + }, + { + name: 'Pending Validation', + value: 'PENDING_VALIDATION', + }, + { + name: 'Revoked', + value: 'REVOKED', + }, + { + name: 'Validation Timed Out', + value: 'VALIDATION_TIMED_OUT', + }, + ], + default: [], + description: 'Filter the certificate list by status value', + }, + { + displayName: 'Extended Key Usage', + name: 'extendedKeyUsage', + type: 'multiOptions', + options: [ + { + name: 'Any', + value: 'ANY', + }, + { + name: 'Code Signing', + value: 'CODE_SIGNING', + }, + { + name: 'Custom', + value: 'CUSTOM', + }, + { + name: 'Email Protection', + value: 'EMAIL_PROTECTION', + }, + { + name: 'IPSEC End System', + value: 'IPSEC_END_SYSTEM', + }, + { + name: 'IPSEC Tunnel', + value: 'IPSEC_TUNNEL', + }, + { + name: 'IPSEC User', + value: 'IPSEC_USER', + }, + { + name: 'None', + value: 'NONE', + }, + { + name: 'OCSP Signing', + value: 'OCSP_SIGNING', + }, + { + name: 'Time Stamping', + value: 'TIME_STAMPING', + }, + { + name: 'TLS Web Client Authentication', + value: 'TLS_WEB_CLIENT_AUTHENTICATION', + }, + { + name: 'TLS Web Server Authentication', + value: 'TLS_WEB_SERVER_AUTHENTICATION', + }, + ], + default: [], + description: 'Specify one or more ExtendedKeyUsage extension values', + }, + { + displayName: 'Key Types', + name: 'keyTypes', + type: 'multiOptions', + options: [ + { + name: 'EC Prime256v1', + value: 'EC_prime256v1', + }, + { + name: 'EC Secp384r1', + value: 'EC_secp384r1', + }, + { + name: 'EC Secp521r1', + value: 'EC_secp521r1', + }, + { + name: 'RSA 1024', + value: 'RSA_1024', + }, + { + name: 'RSA 2048', + value: 'RSA_2048', + }, + { + name: 'RSA 4096', + value: 'RSA_4096', + }, + ], + default: ['RSA_2048'], + description: 'Specify one or more algorithms that can be used to generate key pairs', + }, + { + displayName: 'Key Usage', + name: 'keyUsage', + type: 'multiOptions', + options: [ + { + name: 'Any', + value: 'ANY', + }, + { + name: 'Certificate Signing', + value: 'CERTIFICATE_SIGNING', + }, + { + name: 'CRL Signing', + value: 'CRL_SIGNING', + }, + { + name: 'Custom', + value: 'CUSTOM', + }, + { + name: 'Data Encipherment', + value: 'DATA_ENCIPHERMENT', + }, + { + name: 'Decipher Only', + value: 'DECIPHER_ONLY', + }, + { + name: 'Digital Signature', + value: 'DIGITAL_SIGNATURE', + }, + { + name: 'Encipher Only', + value: 'ENCIPHER_ONLY', + }, + { + name: 'Key Agreement', + value: 'KEY_AGREEMENT', + }, + { + name: 'Key Encipherment', + value: 'KEY_ENCIPHERMENT', + }, + { + name: 'Non Repudiation', + value: 'NON_REPUDIATION', + }, + ], + default: [], + description: 'Specify one or more KeyUsage extension values', + }, + ], + }, +]; diff --git a/packages/nodes-base/nodes/Aws/CertificateManager/GenericFunctions.ts b/packages/nodes-base/nodes/Aws/CertificateManager/GenericFunctions.ts new file mode 100644 index 00000000000..e9beb709ef7 --- /dev/null +++ b/packages/nodes-base/nodes/Aws/CertificateManager/GenericFunctions.ts @@ -0,0 +1,96 @@ +import { get } from 'lodash'; + +import { + IExecuteFunctions, + IHookFunctions, + ILoadOptionsFunctions, + IWebhookFunctions, +} from 'n8n-core'; + +import { IDataObject, IHttpRequestOptions, NodeApiError } from 'n8n-workflow'; + +export async function awsApiRequest( + this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, + service: string, + method: string, + path: string, + body?: string | Buffer, + query: IDataObject = {}, + headers?: object, + // tslint:disable-next-line:no-any + ): Promise { + const credentials = await this.getCredentials('aws'); + + const requestOptions = { + qs: { + service, + path, + ...query, + }, + headers, + method, + url: '', + body, + region: credentials?.region as string, + } as IHttpRequestOptions; + + try { + return await this.helpers.requestWithAuthentication.call(this, 'aws', requestOptions); + } catch (error) { + throw new NodeApiError(this.getNode(), error); + } +} + +export async function awsApiRequestREST( + this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, + service: string, + method: string, + path: string, + body?: string, + query: IDataObject = {}, + headers?: object, + // tslint:disable-next-line:no-any + ): Promise { + const response = await awsApiRequest.call(this, service, method, path, body, query, headers); + try { + return JSON.parse(response); + } catch (e) { + return response; + } +} + +export async function awsApiRequestAllItems( + this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, + propertyName: string, + service: string, + method: string, + path: string, + body?: string, + query: IDataObject = {}, + headers: IDataObject = {}, + // tslint:disable-next-line:no-any +): Promise { + + const returnData: IDataObject[] = []; + + let responseData; + + do { + responseData = await awsApiRequestREST.call( + this, + service, + method, + path, + body, + query, + headers, + ); + if (responseData.NextToken) { + const data = JSON.parse(body as string); + data['NextToken'] = responseData.NextToken; + } + returnData.push.apply(returnData, get(responseData, propertyName)); + } while (responseData.NextToken !== undefined); + + return returnData; +} diff --git a/packages/nodes-base/nodes/Aws/CertificateManager/acm.svg b/packages/nodes-base/nodes/Aws/CertificateManager/acm.svg new file mode 100644 index 00000000000..22d4e0e7cb1 --- /dev/null +++ b/packages/nodes-base/nodes/Aws/CertificateManager/acm.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index f2db52bec00..1f643f929e2 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -360,6 +360,7 @@ "dist/nodes/Aws/AwsLambda.node.js", "dist/nodes/Aws/AwsSns.node.js", "dist/nodes/Aws/AwsSnsTrigger.node.js", + "dist/nodes/Aws/CertificateManager/AwsCertificateManager.node.js", "dist/nodes/Aws/Comprehend/AwsComprehend.node.js", "dist/nodes/Aws/DynamoDB/AwsDynamoDB.node.js", "dist/nodes/Aws/ELB/AwsElb.node.js", From 7abc7e64082b60fa48f99f4b1f41d176fbb6d6ad Mon Sep 17 00:00:00 2001 From: Ricardo Espinoza Date: Fri, 7 Oct 2022 09:10:02 -0400 Subject: [PATCH 549/609] feat(Citrix ADC): add Citrix ADC node (#4274) * :sparkles: Citrix ADC node * :bug: Fix typo in codex file * :zap: Remove trailing slash if there is one * :zap: Add certificate resource * :bug: Fix merge conflict issue --- .../credentials/CitrixAdcApi.credentials.ts | 55 ++++ .../Citrix/ADC/CertificateDescription.ts | 308 ++++++++++++++++++ .../nodes/Citrix/ADC/CitrixAdc.node.json | 18 + .../nodes/Citrix/ADC/CitrixAdc.node.ts | 218 +++++++++++++ .../nodes/Citrix/ADC/FileDescription.ts | 128 ++++++++ .../nodes/Citrix/ADC/GenericFunctions.ts | 44 +++ .../nodes-base/nodes/Citrix/ADC/citrix.svg | 50 +++ packages/nodes-base/package.json | 2 + 8 files changed, 823 insertions(+) create mode 100644 packages/nodes-base/credentials/CitrixAdcApi.credentials.ts create mode 100644 packages/nodes-base/nodes/Citrix/ADC/CertificateDescription.ts create mode 100644 packages/nodes-base/nodes/Citrix/ADC/CitrixAdc.node.json create mode 100644 packages/nodes-base/nodes/Citrix/ADC/CitrixAdc.node.ts create mode 100644 packages/nodes-base/nodes/Citrix/ADC/FileDescription.ts create mode 100644 packages/nodes-base/nodes/Citrix/ADC/GenericFunctions.ts create mode 100644 packages/nodes-base/nodes/Citrix/ADC/citrix.svg diff --git a/packages/nodes-base/credentials/CitrixAdcApi.credentials.ts b/packages/nodes-base/credentials/CitrixAdcApi.credentials.ts new file mode 100644 index 00000000000..0bd0496b059 --- /dev/null +++ b/packages/nodes-base/credentials/CitrixAdcApi.credentials.ts @@ -0,0 +1,55 @@ +import { + IAuthenticateGeneric, + ICredentialTestRequest, + ICredentialType, + INodeProperties, +} from 'n8n-workflow'; + +export class CitrixAdcApi implements ICredentialType { + name = 'citrixAdcApi'; + displayName = 'Citrix ADC API'; + documentationUrl = 'citrix'; + properties: INodeProperties[] = [ + { + displayName: 'URL', + name: 'url', + type: 'string', + default: '', + required: true, + }, + { + displayName: 'Username', + name: 'username', + type: 'string', + default: '', + required: true, + }, + { + displayName: 'Password', + name: 'password', + type: 'string', + default: '', + required: true, + typeOptions: { + password: true, + }, + }, + ]; + + authenticate: IAuthenticateGeneric = { + type: 'generic', + properties: { + headers: { + 'X-NITRO-USER': '={{$credentials.username}}', + 'X-NITRO-PASS': '={{$credentials.password}}', + }, + }, + }; + + test: ICredentialTestRequest = { + request: { + baseURL: '={{$credentials.url}}', + url: '/nitro/v1/config/nspartition?view=summary', + }, + }; +} diff --git a/packages/nodes-base/nodes/Citrix/ADC/CertificateDescription.ts b/packages/nodes-base/nodes/Citrix/ADC/CertificateDescription.ts new file mode 100644 index 00000000000..fe17bfa7333 --- /dev/null +++ b/packages/nodes-base/nodes/Citrix/ADC/CertificateDescription.ts @@ -0,0 +1,308 @@ +import { INodeProperties } from 'n8n-workflow'; + +export const certificateDescription: INodeProperties[] = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + noDataExpression: true, + options: [ + { + name: 'Create', + value: 'create', + action: 'Create a certificate', + }, + ], + default: 'create', + displayOptions: { + show: { + resource: ['certificate'], + }, + }, + }, + { + displayName: 'Certificate File Name', + name: 'certificateFileName', + type: 'string', + required: true, + displayOptions: { + show: { + resource: ['certificate'], + operation: ['create'], + }, + }, + default: '', + description: + 'Name for and, optionally, path to the generated certificate file. /nsconfig/ssl/ is the default path.', + }, + { + displayName: 'Certificate Format', + name: 'certificateFormat', + type: 'options', + options: [ + { + name: 'PEM', + value: 'PEM', + }, + { + name: 'DER', + value: 'DER', + }, + ], + required: true, + displayOptions: { + show: { + resource: ['certificate'], + operation: ['create'], + }, + }, + default: 'PEM', + description: 'Format in which the certificate is stored on the appliance', + }, + { + displayName: 'Certificate Type', + name: 'certificateType', + type: 'options', + options: [ + { + name: 'Root-CA', + value: 'ROOT_CERT', + description: + 'You must specify the key file name. The generated Root-CA certificate can be used for signing end-user client or server certificates or to create Intermediate-CA certificates.', + }, + { + name: 'Intermediate-CA', + value: 'INTM_CERT', + description: 'Intermediate-CA certificate', + }, + { + name: 'Server', + value: 'SRVR_CERT', + description: 'SSL server certificate used on SSL servers for end-to-end encryption', + }, + { + name: 'Client', + value: 'CLNT_CERT', + description: 'End-user client certificate used for client authentication', + }, + ], + required: true, + displayOptions: { + show: { + resource: ['certificate'], + operation: ['create'], + }, + }, + default: 'ROOT_CERT', + }, + { + displayName: 'Certificate Request File Name', + name: 'certificateRequestFileName', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: ['create'], + resource: ['certificate'], + }, + }, + description: + 'Name for and, optionally, path to the certificate-signing request (CSR). /nsconfig/ssl/ is the default path.', + }, + { + displayName: 'CA Certificate File Name', + name: 'caCertificateFileName', + type: 'string', + required: true, + displayOptions: { + show: { + resource: ['certificate'], + operation: ['create'], + certificateType: ['INTM_CERT', 'SRVR_CERT', 'CLNT_CERT'], + }, + }, + default: '', + description: + 'Name of the CA certificate file that issues and signs the Intermediate-CA certificate or the end-user client and server certificates', + }, + { + displayName: 'CA Certificate File Format', + name: 'caCertificateFileFormat', + type: 'options', + options: [ + { + name: 'PEM', + value: 'PEM', + }, + { + name: 'DER', + value: 'DER', + }, + ], + required: true, + displayOptions: { + show: { + resource: ['certificate'], + operation: ['create'], + certificateType: ['INTM_CERT', 'SRVR_CERT', 'CLNT_CERT'], + }, + }, + default: 'PEM', + description: 'Format of the CA certificate', + }, + { + displayName: 'CA Private Key File Name', + name: 'caPrivateKeyFileName', + type: 'string', + required: true, + displayOptions: { + show: { + resource: ['certificate'], + operation: ['create'], + certificateType: ['INTM_CERT', 'SRVR_CERT', 'CLNT_CERT'], + }, + }, + default: '', + description: + 'Private key, associated with the CA certificate that is used to sign the Intermediate-CA certificate or the end-user client and server certificate. If the CA key file is password protected, the user is prompted to enter the pass phrase that was used to encrypt the key.', + }, + { + displayName: 'CA Private Key File Format', + name: 'caPrivateKeyFileFormat', + type: 'options', + options: [ + { + name: 'PEM', + value: 'PEM', + }, + { + name: 'DER', + value: 'DER', + }, + ], + required: true, + displayOptions: { + show: { + resource: ['certificate'], + operation: ['create'], + certificateType: ['INTM_CERT', 'SRVR_CERT', 'CLNT_CERT'], + }, + }, + default: 'PEM', + description: 'Format of the CA certificate', + }, + { + displayName: 'Private Key File Name', + name: 'privateKeyFileName', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: ['create'], + resource: ['certificate'], + certificateType: ['ROOT_CERT'], + }, + }, + description: + 'Name for and, optionally, path to the private key. You can either use an existing RSA or DSA key that you own or create a new private key on the Citrix ADC. This file is required only when creating a self-signed Root-CA certificate. The key file is stored in the /nsconfig/ssl directory by default.', + }, + { + displayName: 'CA Serial File Number', + name: 'caSerialFileNumber', + type: 'string', + required: true, + displayOptions: { + show: { + resource: ['certificate'], + operation: ['create'], + certificateType: ['INTM_CERT', 'SRVR_CERT', 'CLNT_CERT'], + }, + }, + default: '', + description: 'Serial number file maintained for the CA certificate. This file contains the serial number of the next certificate to be issued or signed by the CA.', + }, + { + displayName: 'Private Key Format', + name: 'privateKeyFormat', + type: 'options', + options: [ + { + name: 'PEM', + value: 'PEM', + }, + { + name: 'DER', + value: 'DER', + }, + ], + required: true, + displayOptions: { + show: { + resource: ['certificate'], + operation: ['create'], + certificateType: ['ROOT_CERT'], + }, + }, + default: 'PEM', + description: 'Format in which the key is stored on the appliance', + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: ['certificate'], + operation: ['create'], + }, + }, + options: [ + { + displayName: 'PEM Passphrase (For Encrypted Key)', + name: 'pempassphrase', + type: 'string', + displayOptions: { + show: { + '/certificateType': ['ROOT_CERT'], + }, + }, + default: '', + description: + 'Name for and, optionally, path to the private key. You can either use an existing RSA or DSA key that you own or create a new private key on the Citrix ADC. This file is required only when creating a self-signed Root-CA certificate. The key file is stored in the /nsconfig/ssl directory by default.', + }, + { + displayName: 'PEM Passphrase (For Encrypted CA Key)', + name: 'pempassphrase', + type: 'string', + displayOptions: { + hide: { + '/certificateType': ['ROOT_CERT'], + }, + }, + default: '', + description: + 'Name for and, optionally, path to the private key. You can either use an existing RSA or DSA key that you own or create a new private key on the Citrix ADC. This file is required only when creating a self-signed Root-CA certificate. The key file is stored in the /nsconfig/ssl directory by default.', + }, + { + displayName: 'Subject Alternative Name', + name: 'subjectaltname', + type: 'string', + default: '', + description: + 'Subject Alternative Name (SAN) is an extension to X.509 that allows various values to be associated with a security certificate using a subjectAltName field', + }, + { + displayName: 'Validity Period (Number of Days)', + name: 'days', + type: 'string', + default: '', + description: + 'Number of days for which the certificate will be valid, beginning with the time and day (system time) of creation', + }, + ], + }, +]; diff --git a/packages/nodes-base/nodes/Citrix/ADC/CitrixAdc.node.json b/packages/nodes-base/nodes/Citrix/ADC/CitrixAdc.node.json new file mode 100644 index 00000000000..482c858b1dc --- /dev/null +++ b/packages/nodes-base/nodes/Citrix/ADC/CitrixAdc.node.json @@ -0,0 +1,18 @@ +{ + "node": "n8n-nodes-base.citrixAdc", + "nodeVersion": "1.0", + "codexVersion": "1.0", + "categories": ["Development"], + "resources": { + "credentialDocumentation": [ + { + "url": "https://docs.n8n.io/credentials/citrixAdc" + } + ], + "primaryDocumentation": [ + { + "url": "https://docs.n8n.io/nodes/n8n-nodes-base.citrixAdc/" + } + ] + } +} diff --git a/packages/nodes-base/nodes/Citrix/ADC/CitrixAdc.node.ts b/packages/nodes-base/nodes/Citrix/ADC/CitrixAdc.node.ts new file mode 100644 index 00000000000..6ae9bac31a9 --- /dev/null +++ b/packages/nodes-base/nodes/Citrix/ADC/CitrixAdc.node.ts @@ -0,0 +1,218 @@ +import { IExecuteFunctions } from 'n8n-core'; + +import { + IDataObject, + INodeExecutionData, + INodeType, + INodeTypeDescription, + JsonObject, + NodeOperationError, +} from 'n8n-workflow'; + +import { citrixADCApiRequest } from './GenericFunctions'; + +import { fileDescription } from './FileDescription'; + +import { certificateDescription } from './CertificateDescription'; + +export class CitrixAdc implements INodeType { + description: INodeTypeDescription = { + displayName: 'Citrix ADC', + name: 'citrixAdc', + icon: 'file:citrix.svg', + group: ['output'], + version: 1, + subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', + description: 'Consume Citrix ADC API', + defaults: { + name: 'Citrix ADC', + }, + credentials: [ + { + name: 'citrixAdcApi', + required: true, + }, + ], + inputs: ['main'], + outputs: ['main'], + properties: [ + { + displayName: 'Resource', + name: 'resource', + type: 'options', + noDataExpression: true, + options: [ + { + name: 'Certificate', + value: 'certificate', + }, + { + name: 'File', + value: 'file', + }, + ], + default: 'file', + }, + ...certificateDescription, + ...fileDescription, + ], + }; + + async execute(this: IExecuteFunctions): Promise { + const items = this.getInputData(); + const returnData: IDataObject[] = []; + const resource = this.getNodeParameter('resource', 0) as string; + const operation = this.getNodeParameter('operation', 0) as string; + let responseData: IDataObject | IDataObject[] = {}; + + for (let i = 0; i < items.length; i++) { + try { + if (resource === 'file') { + if (operation === 'upload') { + const fileLocation = this.getNodeParameter('fileLocation', i) as string; + const binaryProperty = this.getNodeParameter('binaryProperty', i) as string; + const options = this.getNodeParameter('options', i) as IDataObject; + const endpoint = `/config/systemfile`; + + const item = items[i]; + + if (item.binary === undefined) { + throw new NodeOperationError(this.getNode(), 'No binary data exists on item!'); + } + + if (item.binary[binaryProperty] === undefined) { + throw new NodeOperationError( + this.getNode(), + `No binary data property "${binaryProperty}" does not exists on item!`, + ); + } + + const buffer = await this.helpers.getBinaryDataBuffer(i, binaryProperty); + + const body = { + systemfile: { + filename: item.binary[binaryProperty].fileName, + filecontent: Buffer.from(buffer).toString('base64'), + filelocation: fileLocation, + fileencoding: 'BASE64', + }, + }; + + if (options.fileName) { + body.systemfile.filename = options.fileName as string; + } + + await citrixADCApiRequest.call(this, 'POST', endpoint, body); + responseData = { success: true }; + } + if (operation === 'delete') { + const fileName = this.getNodeParameter('fileName', i) as string; + const fileLocation = this.getNodeParameter('fileLocation', i) as string; + + const endpoint = `/config/systemfile?args=filename:${fileName},filelocation:${encodeURIComponent( + fileLocation, + )}`; + + await citrixADCApiRequest.call(this, 'DELETE', endpoint); + responseData = { success: true }; + } + if (operation === 'download') { + const fileName = this.getNodeParameter('fileName', i) as string; + const fileLocation = this.getNodeParameter('fileLocation', i) as string; + const binaryProperty = this.getNodeParameter('binaryProperty', i) as string; + + const endpoint = `/config/systemfile?args=filename:${fileName},filelocation:${encodeURIComponent( + fileLocation, + )}`; + + const { systemfile } = await citrixADCApiRequest.call(this, 'GET', endpoint); + + const file = systemfile[0]; + + const binaryData = await this.helpers.prepareBinaryData( + Buffer.from(file.filecontent, 'base64'), + file.filename, + ); + + responseData = { + json: file, + binary: { + [binaryProperty]: binaryData, + }, + }; + } + } + + if (resource === 'certificate') { + if (operation === 'create') { + const certificateFileName = this.getNodeParameter('certificateFileName', i) as string; + const certificateFormat = this.getNodeParameter('certificateFormat', i) as string; + const certificateType = this.getNodeParameter('certificateType', i) as string; + const certificateRequestFileName = this.getNodeParameter( + 'certificateRequestFileName', + i, + ) as string; + const additionalFields = this.getNodeParameter( + 'additionalFields', + i, + {}, + ) as IDataObject; + + let body: IDataObject = { + reqfile: certificateRequestFileName, + certfile: certificateFileName, + certform: certificateFormat, + certType: certificateType, + ...additionalFields, + }; + + if (certificateType === 'ROOT_CERT') { + const privateKeyFileName = this.getNodeParameter('privateKeyFileName', i) as string; + body = { + ...body, + keyfile: privateKeyFileName, + }; + + } else { + const caCertificateFileName = this.getNodeParameter('caCertificateFileName', i) as string; + const caCertificateFileFormat = this.getNodeParameter('caCertificateFileFormat', i) as string; + const caPrivateKeyFileFormat = this.getNodeParameter('caPrivateKeyFileFormat', i) as string; + const caPrivateKeyFileName = this.getNodeParameter('caPrivateKeyFileName', i) as string; + const caSerialFileNumber = this.getNodeParameter('caSerialFileNumber', i) as string; + + body = { + ...body, + cacert: caCertificateFileName, + cacertform: caCertificateFileFormat, + cakey: caPrivateKeyFileName, + cakeyform: caPrivateKeyFileFormat, + caserial: caSerialFileNumber, + }; + } + + const endpoint = `/config/sslcert?action=create`; + + await citrixADCApiRequest.call(this, 'POST', endpoint, { sslcert: body }); + + responseData = { success: true }; + } + } + + returnData.push( + ...this.helpers.constructExecutionMetaData(this.helpers.returnJsonArray(responseData), { + itemData: { item: i }, + }), + ); + } catch (error) { + if (this.continueOnFail()) { + returnData.push({ error: (error as JsonObject).toString() }); + continue; + } + + throw error; + } + } + + return [returnData as INodeExecutionData[]]; + } +} diff --git a/packages/nodes-base/nodes/Citrix/ADC/FileDescription.ts b/packages/nodes-base/nodes/Citrix/ADC/FileDescription.ts new file mode 100644 index 00000000000..865e9492bcb --- /dev/null +++ b/packages/nodes-base/nodes/Citrix/ADC/FileDescription.ts @@ -0,0 +1,128 @@ +import { INodeProperties } from 'n8n-workflow'; + +export const fileDescription: INodeProperties[] = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + noDataExpression: true, + options: [ + { + name: 'Delete', + value: 'delete', + action: 'Delete a file', + }, + { + name: 'Download', + value: 'download', + action: 'Download a file', + }, + { + name: 'Upload', + value: 'upload', + action: 'Upload a file', + }, + ], + default: 'upload', + displayOptions: { + show: { + resource: [ + 'file', + ], + }, + }, + }, + // Upload -------------------------------------------------------------------------- + { + displayName: 'File Location', + name: 'fileLocation', + type: 'string', + required: true, + displayOptions: { + show: { + operation: ['upload'], + resource: ['file'], + }, + }, + default: '/nsconfig/ssl/', + }, + { + displayName: 'Input Data Field Name', + name: 'binaryProperty', + type: 'string', + required: true, + displayOptions: { + show: { + operation: ['upload'], + resource: ['file'], + }, + }, + default: 'data', + description: 'The name of the incoming field containing the binary file data to be processed', + }, + { + displayName: 'Options', + name: 'options', + type: 'collection', + placeholder: 'Add Option', + default: {}, + displayOptions: { + show: { + operation: ['upload'], + resource: ['file'], + }, + }, + options: [ + { + displayName: 'File Name', + name: 'fileName', + type: 'string', + default: '', + description: 'Name of the file. It should not include filepath.', + }, + ], + }, + // Delete, Download --------------------------------------------------------------- + { + displayName: 'File Location', + name: 'fileLocation', + type: 'string', + required: true, + displayOptions: { + show: { + operation: ['delete', 'download' ], + resource: ['file'], + }, + }, + default: '/nsconfig/ssl/', + }, + { + displayName: 'File Name', + name: 'fileName', + type: 'string', + default: '', + required: true, + description: 'Name of the file. It should not include filepath.', + displayOptions: { + show: { + operation: ['delete', 'download' ], + resource: ['file'], + }, + }, + }, + { + displayName: 'Put Output in Field', + name: 'binaryProperty', + type: 'string', + required: true, + default: 'data', + description: + 'The name of the output field to put the binary file data in', + displayOptions: { + show: { + operation: ['download' ], + resource: ['file'], + }, + }, + }, +]; diff --git a/packages/nodes-base/nodes/Citrix/ADC/GenericFunctions.ts b/packages/nodes-base/nodes/Citrix/ADC/GenericFunctions.ts new file mode 100644 index 00000000000..b80c81b4733 --- /dev/null +++ b/packages/nodes-base/nodes/Citrix/ADC/GenericFunctions.ts @@ -0,0 +1,44 @@ +import { OptionsWithUri } from 'request'; + +import { IExecuteFunctions, ILoadOptionsFunctions } from 'n8n-core'; + +import { + IDataObject, + IHookFunctions, + IWebhookFunctions, + JsonObject, + NodeApiError, +} from 'n8n-workflow'; + +export async function citrixADCApiRequest( + this: IExecuteFunctions | IWebhookFunctions | IHookFunctions | ILoadOptionsFunctions, + method: string, + resource: string, + body: IDataObject = {}, + qs: IDataObject = {}, + uri?: string, + option: IDataObject = {}, + // tslint:disable-next-line:no-any + ): Promise { + + const { url } = (await this.getCredentials('citrixAdcApi')) as { url: string }; + + let options: OptionsWithUri = { + headers: { + 'Content-Type': 'application/json', + }, + method, + body, + qs, + uri: uri || `${url.replace(new RegExp('/$'), '')}/nitro/v1${resource}`, + json: true, + }; + + options = Object.assign({}, options, option); + + try { + return await this.helpers.requestWithAuthentication.call(this, 'citrixAdcApi', options); + } catch (error) { + throw new NodeApiError(this.getNode(), error as JsonObject); + } +} diff --git a/packages/nodes-base/nodes/Citrix/ADC/citrix.svg b/packages/nodes-base/nodes/Citrix/ADC/citrix.svg new file mode 100644 index 00000000000..f91f84b508e --- /dev/null +++ b/packages/nodes-base/nodes/Citrix/ADC/citrix.svg @@ -0,0 +1,50 @@ + + + + diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index 1f643f929e2..232658f50c3 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -60,6 +60,7 @@ "dist/credentials/ChargebeeApi.credentials.js", "dist/credentials/CircleCiApi.credentials.js", "dist/credentials/CiscoWebexOAuth2Api.credentials.js", + "dist/credentials/CitrixAdcApi.credentials.js", "dist/credentials/CloudflareApi.credentials.js", "dist/credentials/ClearbitApi.credentials.js", "dist/credentials/ClickUpApi.credentials.js", @@ -387,6 +388,7 @@ "dist/nodes/Chargebee/ChargebeeTrigger.node.js", "dist/nodes/CircleCi/CircleCi.node.js", "dist/nodes/Cisco/Webex/CiscoWebex.node.js", + "dist/nodes/Citrix/ADC/CitrixAdc.node.js", "dist/nodes/Cisco/Webex/CiscoWebexTrigger.node.js", "dist/nodes/Cloudflare/Cloudflare.node.js", "dist/nodes/Clearbit/Clearbit.node.js", From d36e920997d55957385e4ab4d6734639a4c28648 Mon Sep 17 00:00:00 2001 From: Ricardo Espinoza Date: Fri, 7 Oct 2022 09:48:45 -0400 Subject: [PATCH 550/609] feat(Venafi TLS Protect Cloud): add Venafi TLS Protect Cloud (#4253) * :sparkles: Venafi TTL Protect Cloud * :zap: Improvements * :zap: Add authenticate generic type * :zap: Add paired items * :zap: Add codex * :zap: Update package.json --- package-lock.json | 26 + .../VenafiTlsProtectCloudApi.credentials.ts | 35 ++ .../ProtectCloud/CertificateDescription.ts | 398 ++++++++++++++ .../ProtectCloud/CertificateInterface.ts | 41 ++ .../CertificateRequestDescription.ts | 388 ++++++++++++++ .../Venafi/ProtectCloud/GenericFunctions.ts | 146 ++++++ .../VenafiTlsProtectCloud.node.json | 18 + .../VenafiTlsProtectCloud.node.ts | 488 ++++++++++++++++++ .../VenafiTlsProtectCloudTrigger.node.ts | 101 ++++ packages/nodes-base/nodes/Venafi/venafi.svg | 1 + packages/nodes-base/package.json | 4 + 11 files changed, 1646 insertions(+) create mode 100644 packages/nodes-base/credentials/VenafiTlsProtectCloudApi.credentials.ts create mode 100644 packages/nodes-base/nodes/Venafi/ProtectCloud/CertificateDescription.ts create mode 100644 packages/nodes-base/nodes/Venafi/ProtectCloud/CertificateInterface.ts create mode 100644 packages/nodes-base/nodes/Venafi/ProtectCloud/CertificateRequestDescription.ts create mode 100644 packages/nodes-base/nodes/Venafi/ProtectCloud/GenericFunctions.ts create mode 100644 packages/nodes-base/nodes/Venafi/ProtectCloud/VenafiTlsProtectCloud.node.json create mode 100644 packages/nodes-base/nodes/Venafi/ProtectCloud/VenafiTlsProtectCloud.node.ts create mode 100644 packages/nodes-base/nodes/Venafi/ProtectCloud/VenafiTlsProtectCloudTrigger.node.ts create mode 100644 packages/nodes-base/nodes/Venafi/venafi.svg diff --git a/package-lock.json b/package-lock.json index 0193f52c328..daf3fb0ee63 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8498,6 +8498,11 @@ "integrity": "sha512-uaht4XcYSq5ZrPriQW8C+g5DhptewRd1E84ph7L167sCyzLObz+U3JTpmYq/CNkvjNsz2mtyQoHPNEYQYTzWmg==", "dev": true }, + "node_modules/@types/js-nacl": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@types/js-nacl/-/js-nacl-1.3.0.tgz", + "integrity": "sha512-juUvxo444ZfwDSwWyhssMxSN+snqTdiUoOVXZF+/ffVrGHq3rAf1fmczWn3z9TCEAuRbaTmgAcYlZ9MutyyOkQ==" + }, "node_modules/@types/json-diff": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/@types/json-diff/-/json-diff-0.5.2.tgz", @@ -46250,12 +46255,25 @@ "@types/vorpal": "^1.11.0" } }, + "packages/node-dev/node_modules/typescript": { + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", + "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, "packages/nodes-base": { "name": "n8n-nodes-base", "version": "0.194.0", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { "@kafkajs/confluent-schema-registry": "1.0.6", + "@types/js-nacl": "^1.3.0", "amqplib": "^0.8.0", "aws4": "^1.8.0", "basic-auth": "^2.0.1", @@ -46275,6 +46293,7 @@ "imap-simple": "^4.3.0", "isbot": "^3.3.4", "iso-639-1": "^2.1.3", + "js-nacl": "^1.4.0", "jsonwebtoken": "^8.5.1", "kafkajs": "^1.14.0", "lodash.get": "^4.4.2", @@ -54844,6 +54863,11 @@ "integrity": "sha512-uaht4XcYSq5ZrPriQW8C+g5DhptewRd1E84ph7L167sCyzLObz+U3JTpmYq/CNkvjNsz2mtyQoHPNEYQYTzWmg==", "dev": true }, + "@types/js-nacl": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@types/js-nacl/-/js-nacl-1.3.0.tgz", + "integrity": "sha512-juUvxo444ZfwDSwWyhssMxSN+snqTdiUoOVXZF+/ffVrGHq3rAf1fmczWn3z9TCEAuRbaTmgAcYlZ9MutyyOkQ==" + }, "@types/json-diff": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/@types/json-diff/-/json-diff-0.5.2.tgz", @@ -74246,6 +74270,7 @@ "@types/gm": "^1.18.2", "@types/imap-simple": "^4.2.0", "@types/jest": "^27.4.0", + "@types/js-nacl": "^1.3.0", "@types/jsonwebtoken": "^8.5.2", "@types/lodash.set": "^4.3.6", "@types/lossless-json": "^1.0.0", @@ -74285,6 +74310,7 @@ "isbot": "^3.3.4", "iso-639-1": "^2.1.3", "jest": "^27.4.7", + "js-nacl": "^1.4.0", "jsonwebtoken": "^8.5.1", "kafkajs": "^1.14.0", "lodash.get": "^4.4.2", diff --git a/packages/nodes-base/credentials/VenafiTlsProtectCloudApi.credentials.ts b/packages/nodes-base/credentials/VenafiTlsProtectCloudApi.credentials.ts new file mode 100644 index 00000000000..91488a6e9c1 --- /dev/null +++ b/packages/nodes-base/credentials/VenafiTlsProtectCloudApi.credentials.ts @@ -0,0 +1,35 @@ +import { + IAuthenticateGeneric, + ICredentialDataDecryptedObject, + ICredentialTestRequest, + ICredentialType, + IHttpRequestOptions, + NodePropertyTypes, +} from 'n8n-workflow'; + +export class VenafiTlsProtectCloudApi implements ICredentialType { + name = 'venafiTlsProtectCloudApi'; + displayName = 'Venafi TLS Protect Cloud'; + properties = [ + { + displayName: 'API Key', + name: 'apiKey', + type: 'string' as NodePropertyTypes, + default: '', + }, + ]; + authenticate: IAuthenticateGeneric = { + type: 'generic', + properties: { + headers: { + 'tppl-api-key': '={{$credentials.apiKey}}', + }, + }, + }; + test: ICredentialTestRequest = { + request: { + baseURL: 'https://api.venafi.cloud', + url: '/v1/preferences', + }, + }; +} diff --git a/packages/nodes-base/nodes/Venafi/ProtectCloud/CertificateDescription.ts b/packages/nodes-base/nodes/Venafi/ProtectCloud/CertificateDescription.ts new file mode 100644 index 00000000000..d813c717181 --- /dev/null +++ b/packages/nodes-base/nodes/Venafi/ProtectCloud/CertificateDescription.ts @@ -0,0 +1,398 @@ +import { INodeProperties } from 'n8n-workflow'; + +export const certificateOperations: INodeProperties[] = [ + { + displayName: 'Operation', + name: 'operation', + noDataExpression: true, + type: 'options', + displayOptions: { + show: { + resource: ['certificate'], + }, + }, + options: [ + { + name: 'Delete', + value: 'delete', + description: 'Delete a certificate', + action: 'Delete a certificate', + }, + { + name: 'Download', + value: 'download', + description: 'Download a certificate', + action: 'Download a certificate', + }, + { + name: 'Get', + value: 'get', + description: 'Retrieve a certificate', + action: 'Get a certificate', + }, + { + name: 'Get Many', + value: 'getMany', + description: 'Retrieve many certificates', + action: 'Get many certificates', + }, + { + name: 'Renew', + value: 'renew', + description: 'Renew a certificate', + action: 'Renew a certificate', + }, + ], + default: 'delete', + }, +]; + +export const certificateFields: INodeProperties[] = [ + /* -------------------------------------------------------------------------- */ + /* certificate:download */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Certificate ID', + name: 'certificateId', + type: 'string', + required: true, + displayOptions: { + show: { + operation: ['download'], + resource: ['certificate'], + }, + }, + default: '', + }, + { + displayName: 'Download Item', + name: 'downloadItem', + type: 'options', + options: [ + { + name: 'Certificate', + value: 'certificate', + }, + { + name: 'Keystore', + value: 'keystore', + }, + ], + displayOptions: { + show: { + operation: ['download'], + resource: ['certificate'], + }, + }, + default: 'certificate', + }, + { + displayName: 'Keystore Type', + name: 'keystoreType', + type: 'options', + options: [ + { + name: 'JKS', + value: 'JKS', + }, + { + name: 'PKCS12', + value: 'PKCS12', + }, + { + name: 'PEM', + value: 'PEM', + }, + ], + default: 'PEM', + displayOptions: { + show: { + operation: ['download'], + resource: ['certificate'], + downloadItem: ['keystore'], + }, + }, + }, + { + displayName: 'Certificate Label', + name: 'certificateLabel', + type: 'string', + required: true, + displayOptions: { + show: { + operation: ['download'], + resource: ['certificate'], + downloadItem: ['keystore'], + }, + }, + default: '', + }, + { + displayName: 'Private Key Passphrase', + name: 'privateKeyPassphrase', + type: 'string', + required: true, + displayOptions: { + show: { + operation: ['download'], + resource: ['certificate'], + downloadItem: ['keystore'], + }, + }, + default: '', + }, + { + displayName: 'Keystore Passphrase', + name: 'keystorePassphrase', + type: 'string', + required: true, + displayOptions: { + show: { + operation: ['download'], + resource: ['certificate'], + downloadItem: ['keystore'], + keystoreType: ['JKS'], + }, + }, + default: '', + }, + { + displayName: 'Input Data Field Name', + name: 'binaryProperty', + type: 'string', + default: 'data', + displayOptions: { + show: { + operation: ['download'], + resource: ['certificate'], + }, + }, + required: true, + description: + 'The name of the input field containing the binary file data to be uploaded', + }, + { + displayName: 'Options', + name: 'options', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + operation: ['download'], + resource: ['certificate'], + }, + }, + options: [ + { + displayName: 'Chain Order', + name: 'chainOrder', + type: 'options', + options: [ + { + name: 'EE_FIRST', + value: 'EE_FIRST', + description: 'Download the certificate with the end-entity portion of the chain first', + }, + { + name: 'EE_ONLY', + value: 'EE_ONLY', + description: 'Download only the end-entity certificate', + }, + { + name: 'ROOT_FIRST', + value: 'ROOT_FIRST', + description: 'Download the certificate with root portion of the chain first', + }, + ], + default: 'ROOT_FIRST', + }, + { + displayName: 'Format', + name: 'format', + type: 'options', + options: [ + { + name: 'PEM', + value: 'PEM', + }, + { + name: 'DER', + value: 'DER', + }, + ], + default: 'PEM', + }, + ], + }, + /* -------------------------------------------------------------------------- */ + /* certificate:get */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Certificate ID', + name: 'certificateId', + type: 'string', + required: true, + displayOptions: { + show: { + operation: ['get', 'delete'], + resource: ['certificate'], + }, + }, + default: '', + }, + /* -------------------------------------------------------------------------- */ + /* certificate:getMany */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + operation: ['getMany'], + resource: ['certificate'], + }, + }, + default: false, + description: 'Whether to return all results or only up to a given limit', + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + displayOptions: { + show: { + operation: ['getMany'], + resource: ['certificate'], + returnAll: [false], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 500, + }, + default: 50, + description: 'Max number of results to return', + }, + { + displayName: 'Filters', + name: 'filters', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + operation: ['getMany'], + resource: ['certificate'], + }, + }, + options: [ + { + displayName: 'Subject', + name: 'subject', + type: 'string', + default: '', + }, + ], + }, + /* -------------------------------------------------------------------------- */ + /* certificate:renew */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Application Name or ID', + name: 'applicationId', + type: 'options', + description: + 'Choose from the list, or specify an ID using an expression', + typeOptions: { + loadOptionsMethod: 'getApplications', + }, + displayOptions: { + show: { + operation: ['renew'], + resource: ['certificate'], + }, + }, + default: '', + }, + { + displayName: 'Existing Certificate ID', + name: 'existingCertificateId', + type: 'string', + displayOptions: { + show: { + operation: ['renew'], + resource: ['certificate'], + }, + }, + default: '', + }, + { + displayName: 'Certificate Issuing Template Name or ID', + name: 'certificateIssuingTemplateId', + type: 'options', + description: + 'Choose from the list, or specify an ID using an expression', + typeOptions: { + loadOptionsMethod: 'getCertificateIssuingTemplates', + }, + displayOptions: { + show: { + operation: ['renew'], + resource: ['certificate'], + }, + }, + default: '', + }, + { + displayName: 'Certificate Signing Request', + name: 'certificateSigningRequest', + type: 'string', + typeOptions: { + alwaysOpenEditWindow: true, + }, + displayOptions: { + show: { + operation: ['renew'], + resource: ['certificate'], + }, + }, + default: '', + }, + { + displayName: 'Options', + name: 'options', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + operation: ['renew'], + resource: ['certificate'], + }, + }, + options: [ + { + displayName: 'Validity Period', + name: 'validityPeriod', + type: 'options', + options: [ + { + name: '1 Year', + value: 'P1Y', + }, + { + name: '10 Days', + value: 'P10D', + }, + { + name: '12 Hours', + value: 'PT12H', + }, + ], + default: 'P1Y', + }, + ], + }, +]; diff --git a/packages/nodes-base/nodes/Venafi/ProtectCloud/CertificateInterface.ts b/packages/nodes-base/nodes/Venafi/ProtectCloud/CertificateInterface.ts new file mode 100644 index 00000000000..53d41cc404e --- /dev/null +++ b/packages/nodes-base/nodes/Venafi/ProtectCloud/CertificateInterface.ts @@ -0,0 +1,41 @@ +export interface ICertficateRequest { + isVaaSGenerated?: boolean; + csrAttributes?: ICsrAttributes; + applicationServerTypeId?: string; + certificateSigningRequest?: string; + applicationId?: string; + certificateIssuingTemplateId?: string; + certficateOwnerUserId?: string; + validityPeriod?: string; +} + +export interface ICsrAttributes { + commonName?: string; + organization?: string; + organizationalUnits?: string[]; + locality?: string; + state?: string; + country?: string; + keyTypeParameters?: IKeyTypeParameters; + subjectAlternativeNamesByType?: ISubjectAltNamesByType; +} + +export interface IKeyTypeParameters { + keyType?: string; + keyCurve?: string; + keyLength?: number; +} + +export interface ISubjectAltNamesByType { + dnsNames?: string[]; + rfc822Names?: string[]; + ipAddresses?: string[]; + uniformResourceIdentifiers?: string[]; +} + +export interface ICertficateKeystoreRequest { + exportFormat?: string; + encryptedPrivateKeyPassphrase?: string; + encryptedKeystorePassphrase?: string; + certificateLabel?: string; +} diff --git a/packages/nodes-base/nodes/Venafi/ProtectCloud/CertificateRequestDescription.ts b/packages/nodes-base/nodes/Venafi/ProtectCloud/CertificateRequestDescription.ts new file mode 100644 index 00000000000..f2d3e9d73e8 --- /dev/null +++ b/packages/nodes-base/nodes/Venafi/ProtectCloud/CertificateRequestDescription.ts @@ -0,0 +1,388 @@ +import { INodeProperties } from 'n8n-workflow'; + +export const certificateRequestOperations: INodeProperties[] = [ + { + displayName: 'Operation', + name: 'operation', + noDataExpression: true, + type: 'options', + displayOptions: { + show: { + resource: ['certificateRequest'], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + description: 'Create a new certificate request', + action: 'Create a certificate request', + }, + { + name: 'Get', + value: 'get', + description: 'Retrieve a certificate request', + action: 'Get a certificate request', + }, + { + name: 'Get Many', + value: 'getMany', + description: 'Retrieve many certificate requests', + action: 'Get many certificate requests', + }, + ], + default: 'create', + }, +]; + +export const certificateRequestFields: INodeProperties[] = [ + /* -------------------------------------------------------------------------- */ + /* certificateRequest:create */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Application Name or ID', + name: 'applicationId', + type: 'options', + description: + 'Choose from the list, or specify an ID using an expression', + typeOptions: { + loadOptionsMethod: 'getApplications', + }, + displayOptions: { + show: { + operation: ['create'], + resource: ['certificateRequest'], + }, + }, + default: '', + }, + { + displayName: 'Certificate Issuing Template Name or ID', + name: 'certificateIssuingTemplateId', + type: 'options', + description: + 'Choose from the list, or specify an ID using an expression', + typeOptions: { + loadOptionsMethod: 'getCertificateIssuingTemplates', + }, + displayOptions: { + show: { + operation: ['create'], + resource: ['certificateRequest'], + }, + }, + default: '', + }, + { + displayName: 'Generate CSR', + name: 'generateCsr', + type: 'boolean', + displayOptions: { + show: { + operation: ['create'], + resource: ['certificateRequest'], + }, + }, + default: false, + }, + { + displayName: 'Application Server Type Name or ID', + name: 'applicationServerTypeId', + type: 'options', + description: + 'Choose from the list, or specify an ID using an expression', + typeOptions: { + loadOptionsMethod: 'getApplicationServerTypes', + }, + displayOptions: { + show: { + operation: ['create'], + resource: ['certificateRequest'], + generateCsr: [true], + }, + }, + default: '', + }, + { + displayName: 'Common Name', + name: 'commonName', + required: true, + displayOptions: { + show: { + operation: ['create'], + resource: ['certificateRequest'], + generateCsr: [true], + }, + }, + type: 'string', + default: 'n8n.io', + description: 'The Common Name field for the certificate Subject (CN)', + }, + // Optional... + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + operation: ['create'], + resource: ['certificateRequest'], + generateCsr: [true], + }, + }, + options: [ + { + displayName: 'Country', + name: 'country', + type: 'string', + default: '', + description: 'A 2 letter country code', + }, + { + displayName: 'Key Curve', + name: 'keyCurve', + type: 'options', + options: [ + { + name: 'ED25519', + value: 'ED25519', + description: 'Use Edwards-curve Digital Signature Algorithm (EdDSA)', + }, + { + name: 'P256', + value: 'P256', + description: 'Use Elliptic Prime Curve 256 bit encryption', + }, + { + name: 'P384', + value: 'P384', + description: 'Use Elliptic Prime Curve 384 bit encryption', + }, + { + name: 'P521', + value: 'P521', + description: 'Use Elliptic Prime Curve 521 bit encryption', + }, + { + name: 'UNKNOWN', + value: 'UNKNOWN', + }, + ], + default: 'ED25519', + }, + { + displayName: 'Key Length', + name: 'keyLength', + type: 'number', + default: 2048, + description: 'The number of bits to allow for key generation', + }, + { + displayName: 'Key Type', + name: 'keyType', + type: 'options', + options: [ + { + name: 'EC', + value: 'EC', + description: 'Elliptic Curve (EC)', + }, + { + name: 'RSA', + value: 'RSA', + description: 'Rivest, Shamir, Adleman key (RSA)', + }, + ], + default: 'RSA', + description: 'The encryption algorithm for the public key', + }, + { + displayName: 'Locality', + name: 'locality', + type: 'string', + default: '', + description: 'The name of a city or town', + }, + { + displayName: 'Organization', + name: 'organization', + type: 'string', + default: '', + description: 'The name of a company or organization', + }, + { + displayName: 'Organizational Units', + name: 'organizationalUnits', + type: 'string', + typeOptions: { + multipleValues: true, + }, + default: '', + description: 'The name of a department or section', + }, + { + displayName: 'State', + name: 'state', + type: 'string', + default: '', + description: 'The name of a state or province', + }, + { + displayName: 'Subject Alt Names', + name: 'SubjectAltNamesUi', + placeholder: 'Add Subject', + type: 'fixedCollection', + default: {}, + typeOptions: { + multipleValues: true, + }, + options: [ + { + name: 'SubjectAltNamesValues', + displayName: 'Subject Alt Name', + values: [ + { + displayName: 'Typename', + name: 'Typename', + type: 'options', + options: [ + { + name: 'DNS', + value: 'dnsNames', + }, + /*{ + name: 'IP Address', + value: 'ipAddresses', + }, + { + name: 'RFC822 Names', + value: 'rfc822Names', + }, + + { + name: 'URI', + value: 'uniformResourceIdentifiers', + },*/ + ], + description: 'What type of SAN is being used', + default: 'dnsNames', + }, + { + displayName: 'Name', + name: 'name', + type: 'string', + default: 'community.n8n.io', + description: + 'The SAN friendly name that corresponds to the Type or TypeName parameter. For example, if a TypeName is IPAddress, the Name value is a valid IP address.', + }, + ], + }, + ], + }, + ], + }, + // End CSR Builder + { + displayName: 'Certificate Signing Request', + name: 'certificateSigningRequest', + type: 'string', + typeOptions: { + alwaysOpenEditWindow: true, + }, + displayOptions: { + show: { + operation: ['create'], + resource: ['certificateRequest'], + generateCsr: [false], + }, + }, + default: '', + }, + { + displayName: 'Options', + name: 'options', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + operation: ['create'], + resource: ['certificateRequest'], + }, + }, + options: [ + { + displayName: 'Validity Period', + name: 'validityPeriod', + type: 'options', + options: [ + { + name: '1 Year', + value: 'P1Y', + }, + { + name: '10 Days', + value: 'P10D', + }, + { + name: '12 Hours', + value: 'PT12H', + }, + ], + default: 'P1Y', + }, + ], + }, + /* -------------------------------------------------------------------------- */ + /* certificateRequest:get */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Certificate Request ID', + name: 'certificateRequestId', + type: 'string', + required: true, + displayOptions: { + show: { + operation: ['get'], + resource: ['certificateRequest'], + }, + }, + default: '', + }, + /* -------------------------------------------------------------------------- */ + /* certificateRequest:getMany */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + operation: ['getMany'], + resource: ['certificateRequest'], + }, + }, + default: false, + description: 'Whether to return all results or only up to a given limit', + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + displayOptions: { + show: { + operation: ['getMany'], + resource: ['certificateRequest'], + returnAll: [false], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 500, + }, + default: 50, + description: 'Max number of results to return', + }, +]; diff --git a/packages/nodes-base/nodes/Venafi/ProtectCloud/GenericFunctions.ts b/packages/nodes-base/nodes/Venafi/ProtectCloud/GenericFunctions.ts new file mode 100644 index 00000000000..678dd9d0a94 --- /dev/null +++ b/packages/nodes-base/nodes/Venafi/ProtectCloud/GenericFunctions.ts @@ -0,0 +1,146 @@ +import { OptionsWithUri } from 'request'; + +import { + IExecuteFunctions, + IExecuteSingleFunctions, + ILoadOptionsFunctions, + IPollFunctions, +} from 'n8n-core'; + +import { IDataObject, JsonObject, NodeApiError } from 'n8n-workflow'; + +import { get } from 'lodash'; + +import * as nacl_factory from 'js-nacl'; + +export async function venafiApiRequest( + this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IPollFunctions, + method: string, + resource: string, + body = {}, + qs: IDataObject = {}, + uri?: string, + option: IDataObject = {}, + // tslint:disable-next-line:no-any +): Promise { + const operation = this.getNodeParameter('operation', 0) as string; + + const options: OptionsWithUri = { + headers: { + Accept: 'application/json', + 'content-type': 'application/json', + }, + method, + body, + qs, + uri: `https://api.venafi.cloud${resource}`, + json: true, + }; + + if (Object.keys(option).length) { + Object.assign(options, option); + } + + // For cert download we don't need any headers + // If we remove for everything the key fetch fails + if (operation === 'download') { + // We need content-type for keystore + if (!resource.endsWith('keystore')) { + delete options!.headers!['Accept']; + delete options!.headers!['content-type']; + } + } + + try { + if (Object.keys(body).length === 0) { + delete options.body; + } + return await this.helpers.requestWithAuthentication.call( + this, + 'venafiTlsProtectCloudApi', + options, + ); + } catch (error) { + throw new NodeApiError(this.getNode(), error as JsonObject); + } +} + +export async function venafiApiRequestAllItems( + this: IExecuteFunctions | ILoadOptionsFunctions, + propertyName: string, + method: string, + endpoint: string, + // tslint:disable-next-line:no-any + body: any = {}, + query: IDataObject = {}, + // tslint:disable-next-line:no-any +): Promise { + const returnData: IDataObject[] = []; + + let responseData; + + do { + responseData = await venafiApiRequest.call(this, method, endpoint, body, query); + endpoint = get(responseData, '_links[0].Next'); + returnData.push.apply(returnData, responseData[propertyName]); + } while (responseData._links && responseData._links[0].Next); + + return returnData; +} + +export async function encryptPassphrase( + this: IExecuteFunctions | ILoadOptionsFunctions, + certificateId: string, + passphrase: string, + storePassphrase: string, +) { + let dekHash = ''; + const dekResponse = await venafiApiRequest.call( + this, + 'GET', + `/outagedetection/v1/certificates/${certificateId}`, + ); + + if (dekResponse.dekHash) { + dekHash = dekResponse.dekHash; + } + + let pubKey = ''; + const pubKeyResponse = await venafiApiRequest.call( + this, + 'GET', + `/v1/edgeencryptionkeys/${dekHash}`, + ); + + if (pubKeyResponse.key) { + pubKey = pubKeyResponse.key; + } + + let encryptedKeyPass = ''; + let encryptedKeyStorePass = ''; + + const promise = () => { + return new Promise((resolve, reject) => { + // tslint:disable-next-line:no-any + nacl_factory.instantiate((nacl: any) => { + try { + const passphraseUTF8 = nacl.encode_utf8(passphrase) as string; + const keyPassBuffer = nacl.crypto_box_seal(passphraseUTF8, Buffer.from(pubKey, 'base64')); + encryptedKeyPass = Buffer.from(keyPassBuffer).toString('base64'); + + const storePassphraseUTF8 = nacl.encode_utf8(storePassphrase) as string; + const keyStorePassBuffer = nacl.crypto_box_seal( + storePassphraseUTF8, + Buffer.from(pubKey, 'base64'), + ); + encryptedKeyStorePass = Buffer.from(keyStorePassBuffer).toString('base64'); + + return resolve([encryptedKeyPass, encryptedKeyStorePass]); + } catch (error) { + return reject(error); + } + }); + }); + }; + return await promise(); +} diff --git a/packages/nodes-base/nodes/Venafi/ProtectCloud/VenafiTlsProtectCloud.node.json b/packages/nodes-base/nodes/Venafi/ProtectCloud/VenafiTlsProtectCloud.node.json new file mode 100644 index 00000000000..8aaa7e1d1f8 --- /dev/null +++ b/packages/nodes-base/nodes/Venafi/ProtectCloud/VenafiTlsProtectCloud.node.json @@ -0,0 +1,18 @@ +{ + "node": "n8n-nodes-base.venafiTlsProtectCloud", + "nodeVersion": "1.0", + "codexVersion": "1.0", + "categories": ["Development"], + "resources": { + "credentialDocumentation": [ + { + "url": "https://docs.n8n.io/credentials/venafiTlsProtectCloud" + } + ], + "primaryDocumentation": [ + { + "url": "https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.venafiTlsProtectCloud/" + } + ] + } +} diff --git a/packages/nodes-base/nodes/Venafi/ProtectCloud/VenafiTlsProtectCloud.node.ts b/packages/nodes-base/nodes/Venafi/ProtectCloud/VenafiTlsProtectCloud.node.ts new file mode 100644 index 00000000000..ef125f44cef --- /dev/null +++ b/packages/nodes-base/nodes/Venafi/ProtectCloud/VenafiTlsProtectCloud.node.ts @@ -0,0 +1,488 @@ +import { IExecuteFunctions } from 'n8n-core'; + +import { + IDataObject, + ILoadOptionsFunctions, + INodeExecutionData, + INodePropertyOptions, + INodeType, + INodeTypeDescription, +} from 'n8n-workflow'; + +import { encryptPassphrase, venafiApiRequest, venafiApiRequestAllItems } from './GenericFunctions'; + +import { certificateFields, certificateOperations } from './CertificateDescription'; + +import { + certificateRequestFields, + certificateRequestOperations, +} from './CertificateRequestDescription'; + +import { + ICertficateKeystoreRequest, + ICertficateRequest, + ICsrAttributes, + IKeyTypeParameters, + ISubjectAltNamesByType, +} from './CertificateInterface'; + +export class VenafiTlsProtectCloud implements INodeType { + description: INodeTypeDescription = { + displayName: 'Venafi TLS Protect Cloud', + name: 'venafiTlsProtectCloud', + icon: 'file:../venafi.svg', + group: ['input'], + version: 1, + subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', + description: 'Consume Venafi TLS Protect Cloud​ API', + defaults: { + name: 'Venafi TLS Protect Cloud​', + color: '#000000', + }, + inputs: ['main'], + outputs: ['main'], + credentials: [ + { + name: 'venafiTlsProtectCloudApi', + required: true, + }, + ], + properties: [ + { + displayName: 'Resource', + name: 'resource', + noDataExpression: true, + type: 'options', + options: [ + { + name: 'Certificate', + value: 'certificate', + }, + { + name: 'Certificate Request', + value: 'certificateRequest', + }, + ], + default: 'certificateRequest', + }, + ...certificateOperations, + ...certificateFields, + ...certificateRequestOperations, + ...certificateRequestFields, + ], + }; + + methods = { + loadOptions: { + async getApplications(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + const { applications } = await venafiApiRequest.call( + this, + 'GET', + '/outagedetection/v1/applications', + ); + for (const application of applications) { + returnData.push({ + name: application.name, + value: application.id, + }); + } + return returnData; + }, + async getApplicationServerTypes( + this: ILoadOptionsFunctions, + ): Promise { + const returnData: INodePropertyOptions[] = []; + const { applicationServerTypes } = await venafiApiRequest.call( + this, + 'GET', + '/outagedetection/v1/applicationservertypes', + ); + for (const applicationServerType of applicationServerTypes) { + returnData.push({ + name: applicationServerType.platformName, + value: applicationServerType.id, + }); + } + return returnData; + }, + async getCertificateIssuingTemplates( + this: ILoadOptionsFunctions, + ): Promise { + const returnData: INodePropertyOptions[] = []; + const { certificateIssuingTemplates } = await venafiApiRequest.call( + this, + 'GET', + '/v1/certificateissuingtemplates', + ); + for (const issueTemplate of certificateIssuingTemplates) { + returnData.push({ + name: issueTemplate.name, + value: issueTemplate.id, + }); + } + return returnData; + }, + }, + }; + + async execute(this: IExecuteFunctions): Promise { + const items = this.getInputData(); + const returnData: IDataObject[] = []; + const length = items.length; + const qs: IDataObject = {}; + let responseData; + const resource = this.getNodeParameter('resource', 0) as string; + const operation = this.getNodeParameter('operation', 0) as string; + for (let i = 0; i < length; i++) { + try { + if (resource === 'certificateRequest') { + //https://api.venafi.cloud/webjars/swagger-ui/index.html?configUrl=/v3/api-docs/swagger-config&urls.primaryName=outagedetection-service#//v1/certificaterequests_create + if (operation === 'create') { + const applicationId = this.getNodeParameter('applicationId', i) as string; + const certificateIssuingTemplateId = this.getNodeParameter( + 'certificateIssuingTemplateId', + i, + ) as string; + const options = this.getNodeParameter('options', i) as IDataObject; + const generateCsr = this.getNodeParameter('generateCsr', i) as boolean; + + const body: ICertficateRequest = { + applicationId, + certificateIssuingTemplateId, + }; + + if (generateCsr) { + const applicationServerTypeId = this.getNodeParameter( + 'applicationServerTypeId', + i, + ) as string; + const commonName = this.getNodeParameter('commonName', i) as string; + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + + const keyTypeDetails: IKeyTypeParameters = {}; + const csrAttributes: ICsrAttributes = {}; + const subjectAltNamesByType: ISubjectAltNamesByType = {}; + + body.isVaaSGenerated = true; + body.applicationServerTypeId = applicationServerTypeId as string; + + csrAttributes.commonName = commonName as string; + + // Csr Generation + if (additionalFields.organization) { + csrAttributes.organization = additionalFields.organization as string; + } + if (additionalFields.organizationalUnits) { + csrAttributes.organizationalUnits = + additionalFields.organizationalUnits as string[]; + } + if (additionalFields.locality) { + csrAttributes.locality = additionalFields.locality as string; + } + if (additionalFields.state) { + csrAttributes.state = additionalFields.state as string; + } + if (additionalFields.country) { + csrAttributes.country = additionalFields.country as string; + } + body.csrAttributes = csrAttributes; + + // Key type + if (additionalFields.keyType) { + keyTypeDetails.keyType = additionalFields.keyType as string; + } + if (additionalFields.keyCurve) { + keyTypeDetails.keyCurve = additionalFields.keyCurve as string; + } + if (additionalFields.keyLength) { + keyTypeDetails.keyLength = additionalFields.keyLength as number; + } + if (Object.keys(keyTypeDetails).length !== 0) { + body.csrAttributes.keyTypeParameters = keyTypeDetails; + } + + // SAN + if (additionalFields.SubjectAltNamesUi) { + for (const key of (additionalFields.SubjectAltNamesUi as IDataObject) + .SubjectAltNamesValues as IDataObject[]) { + if (key.Typename === 'dnsNames') { + subjectAltNamesByType.dnsNames + ? subjectAltNamesByType.dnsNames.push(key.name as string) + : (subjectAltNamesByType.dnsNames = [key.name as string]); + } + /*if (key.Typename === 'ipAddresses') { + subjectAltNamesByType.ipAddresses ? subjectAltNamesByType.ipAddresses.push(key.name as string) : subjectAltNamesByType.ipAddresses = [key.name as string]; + } + if (key.Typename === 'rfc822Names') { + subjectAltNamesByType.rfc822Names ? subjectAltNamesByType.rfc822Names.push(key.name as string) : subjectAltNamesByType.rfc822Names = [key.name as string]; + } + if (key.Typename === 'uniformResourceIdentifiers') { + subjectAltNamesByType.uniformResourceIdentifiers ? subjectAltNamesByType.uniformResourceIdentifiers.push(key.name as string) : subjectAltNamesByType.uniformResourceIdentifiers = [key.name as string]; + }*/ + } + } + if (Object.keys(subjectAltNamesByType).length !== 0) { + body.csrAttributes.subjectAlternativeNamesByType = subjectAltNamesByType; + } + } else { + const certificateSigningRequest = this.getNodeParameter( + 'certificateSigningRequest', + i, + ) as string; + body.isVaaSGenerated = false; + body.certificateSigningRequest = certificateSigningRequest; + } + + Object.assign(body, options); + + responseData = await venafiApiRequest.call( + this, + 'POST', + `/outagedetection/v1/certificaterequests`, + body, + qs, + ); + + responseData = responseData.certificateRequests; + } + + //https://api.venafi.cloud/webjars/swagger-ui/index.html?configUrl=/v3/api-docs/swagger-config&urls.primaryName=outagedetection-service#//v1/certificaterequests_getById + if (operation === 'get') { + const certificateId = this.getNodeParameter('certificateRequestId', i) as string; + + responseData = await venafiApiRequest.call( + this, + 'GET', + `/outagedetection/v1/certificaterequests/${certificateId}`, + {}, + qs, + ); + } + + //https://api.venafi.cloud/webjars/swagger-ui/index.html?configUrl=/v3/api-docs/swagger-config&urls.primaryName=outagedetection-service#//v1/certificaterequests_getAll + if (operation === 'getMany') { + const returnAll = this.getNodeParameter('returnAll', i) as boolean; + + if (returnAll) { + responseData = await venafiApiRequestAllItems.call( + this, + 'certificateRequests', + 'GET', + `/outagedetection/v1/certificaterequests`, + {}, + qs, + ); + } else { + const limit = this.getNodeParameter('limit', i) as number; + responseData = await venafiApiRequest.call( + this, + 'GET', + `/outagedetection/v1/certificaterequests`, + {}, + qs, + ); + + responseData = responseData.certificateRequests.splice(0, limit); + } + } + } + + if (resource === 'certificate') { + //https://api.venafi.cloud/webjars/swagger-ui/index.html?configUrl=%2Fv3%2Fapi-docs%2Fswagger-config&urls.primaryName=outagedetection-service#/%2Fv1/certificateretirement_deleteCertificates + if (operation === 'delete') { + const certificateId = this.getNodeParameter('certificateId', i) as string; + + responseData = await venafiApiRequest.call( + this, + 'POST', + `/outagedetection/v1/certificates/deletion`, + { certificateIds: [certificateId] }, + ); + + responseData = responseData.certificates; + } + + //https://api.venafi.cloud/webjars/swagger-ui/index.html?configUrl=%2Fv3%2Fapi-docs%2Fswagger-config&urls.primaryName=outagedetection-service#/ + if (operation === 'download') { + const certificateId = this.getNodeParameter('certificateId', i) as string; + const binaryProperty = this.getNodeParameter('binaryProperty', i) as string; + const downloadItem = this.getNodeParameter('downloadItem', i) as string; + const options = this.getNodeParameter('options', i) as IDataObject; + + // Cert Download + if (downloadItem === 'certificate') { + Object.assign(qs, options); + responseData = await venafiApiRequest.call( + this, + 'GET', + `/outagedetection/v1/certificates/${certificateId}/contents`, + {}, + qs, + undefined, + { encoding: null, json: false, resolveWithFullResponse: true, cert: true }, + ); + } else { + const exportFormat = this.getNodeParameter('keystoreType', i) as string; + + const body: ICertficateKeystoreRequest = { + exportFormat, + }; + + const privateKeyPassphrase = this.getNodeParameter( + 'privateKeyPassphrase', + i, + ) as string; + const certificateLabel = this.getNodeParameter('certificateLabel', i) as string; + + body.certificateLabel = certificateLabel; + + let keystorePassphrase = ''; + + if (exportFormat === 'JKS') { + keystorePassphrase = this.getNodeParameter('keystorePassphrase', i) as string; + } + + const encryptedValues = (await encryptPassphrase.call( + this, + certificateId, + privateKeyPassphrase, + keystorePassphrase, + )) as string; + body.encryptedPrivateKeyPassphrase = encryptedValues[0]; + if (exportFormat === 'JKS') { + body.encryptedKeystorePassphrase = encryptedValues[1]; + } + + responseData = await venafiApiRequest.call( + this, + 'POST', + `/outagedetection/v1/certificates/${certificateId}/keystore`, + body, + {}, + undefined, + { encoding: null, json: false, resolveWithFullResponse: true }, + ); + } + + const contentDisposition = responseData.headers['content-disposition']; + const fileNameRegex = /(?<=filename=").*\b/; + const match = fileNameRegex.exec(contentDisposition); + let fileName = ''; + + if (match !== null) { + fileName = match[0]; + } + + const binaryData = await this.helpers.prepareBinaryData( + Buffer.from(responseData.body), + fileName, + ); + + responseData = { + json: {}, + binary: { + [binaryProperty]: binaryData, + }, + }; + } + + //https://api.venafi.cloud/webjars/swagger-ui/index.html?configUrl=%2Fv3%2Fapi-docs%2Fswagger-config&urls.primaryName=outagedetection-service#/%2Fv1/certificates_getById + if (operation === 'get') { + const certificateId = this.getNodeParameter('certificateId', i) as string; + + responseData = await venafiApiRequest.call( + this, + 'GET', + `/outagedetection/v1/certificates/${certificateId}`, + {}, + qs, + ); + } + + //https://api.venafi.cloud/webjars/swagger-ui/index.html?configUrl=%2Fv3%2Fapi-docs%2Fswagger-config&urls.primaryName=outagedetection-service#/%2Fv1/certificates_getAllAsCsv + if (operation === 'getMany') { + const returnAll = this.getNodeParameter('returnAll', i) as boolean; + const filters = this.getNodeParameter('filters', i) as IDataObject; + + Object.assign(qs, filters); + + if (returnAll) { + responseData = await venafiApiRequestAllItems.call( + this, + 'certificates', + 'GET', + `/outagedetection/v1/certificates`, + {}, + qs, + ); + } else { + qs.limit = this.getNodeParameter('limit', i) as number; + responseData = await venafiApiRequest.call( + this, + 'GET', + `/outagedetection/v1/certificates`, + {}, + qs, + ); + + responseData = responseData.certificates; + } + } + + //https://docs.venafi.cloud/api/t-cloud-api-renew-cert/ + if (operation === 'renew') { + const applicationId = this.getNodeParameter('applicationId', i) as string; + const certificateIssuingTemplateId = this.getNodeParameter( + 'certificateIssuingTemplateId', + i, + ) as string; + const certificateSigningRequest = this.getNodeParameter( + 'certificateSigningRequest', + i, + ) as string; + const existingCertificateId = this.getNodeParameter( + 'existingCertificateId', + i, + ) as string; + const options = this.getNodeParameter('options', i) as IDataObject; + + const body: IDataObject = { + certificateSigningRequest, + certificateIssuingTemplateId, + applicationId, + existingCertificateId, + }; + + Object.assign(body, options); + + responseData = await venafiApiRequest.call( + this, + 'POST', + `/outagedetection/v1/certificaterequests`, + body, + qs, + ); + + responseData = responseData.certificateRequests; + } + } + + returnData.push( + ...this.helpers.constructExecutionMetaData(this.helpers.returnJsonArray(responseData), { + itemData: { item: i }, + }), + ); + + } catch (error) { + if (this.continueOnFail()) { + returnData.push({ json: { error: error.message } }); + continue; + } + throw error; + } + } + + return [returnData as INodeExecutionData[]]; + } +} diff --git a/packages/nodes-base/nodes/Venafi/ProtectCloud/VenafiTlsProtectCloudTrigger.node.ts b/packages/nodes-base/nodes/Venafi/ProtectCloud/VenafiTlsProtectCloudTrigger.node.ts new file mode 100644 index 00000000000..8db5ba08ca2 --- /dev/null +++ b/packages/nodes-base/nodes/Venafi/ProtectCloud/VenafiTlsProtectCloudTrigger.node.ts @@ -0,0 +1,101 @@ +import { IPollFunctions } from 'n8n-core'; + +import { INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow'; + +import moment from 'moment'; + +import { venafiApiRequest } from './GenericFunctions'; + +export class VenafiTlsProtectCloudTrigger implements INodeType { + description: INodeTypeDescription = { + displayName: 'Venafi TLS Protect Cloud Trigger', + name: 'venafiTlsProtectCloudTrigger', + icon: 'file:../venafi.svg', + group: ['trigger'], + version: 1, + subtitle: '={{$parameter["triggerOn"]}}', + description: 'Starts the workflow when Venafi events occure', + defaults: { + name: 'Venafi TLS Protect Cloud​', + color: '#000000', + }, + credentials: [ + { + name: 'venafiTlsProtectCloudApi', + required: true, + }, + ], + polling: true, + inputs: [], + outputs: ['main'], + properties: [ + { + displayName: 'Trigger On', + name: 'trigger On', + type: 'options', + options: [ + { + name: 'Certificate Expired', + value: 'certificateExpired', + }, + ], + required: true, + default: 'certificateExpired', + }, + ], + }; + + async poll(this: IPollFunctions): Promise { + const webhookData = this.getWorkflowStaticData('node'); + const event = this.getNodeParameter('event') as string; + + const now = moment().format(); + + const startDate = webhookData.lastTimeChecked || now; + const endDate = now; + + const { certificates: certificates } = await venafiApiRequest.call( + this, + 'POST', + `/outagedetection/v1/certificatesearch`, + { + expression: { + operands: [ + { + operator: 'AND', + operands: [ + { + field: 'validityEnd', + operator: 'LTE', + values: [endDate], + }, + { + field: 'validityEnd', + operator: 'GTE', + values: [startDate], + }, + ], + }, + ], + }, + ordering: { + orders: [ + { + field: 'certificatInstanceModificationDate', + direction: 'DESC', + }, + ], + }, + }, + {}, + ); + + webhookData.lastTimeChecked = endDate; + + if (Array.isArray(certificates) && certificates.length) { + return [this.helpers.returnJsonArray(certificates)]; + } + + return null; + } +} diff --git a/packages/nodes-base/nodes/Venafi/venafi.svg b/packages/nodes-base/nodes/Venafi/venafi.svg new file mode 100644 index 00000000000..70ed4594fa9 --- /dev/null +++ b/packages/nodes-base/nodes/Venafi/venafi.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index 232658f50c3..d31e3404622 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -317,6 +317,7 @@ "dist/credentials/UrlScanIoApi.credentials.js", "dist/credentials/VeroApi.credentials.js", "dist/credentials/VonageApi.credentials.js", + "dist/credentials/VenafiTlsProtectCloudApi.credentials.js", "dist/credentials/VenafiTlsProtectDatacenterApi.credentials.js", "dist/credentials/WebflowApi.credentials.js", "dist/credentials/WebflowOAuth2Api.credentials.js", @@ -686,6 +687,7 @@ "dist/nodes/UptimeRobot/UptimeRobot.node.js", "dist/nodes/UrlScanIo/UrlScanIo.node.js", "dist/nodes/Vero/Vero.node.js", + "dist/nodes/Venafi/ProtectCloud/VenafiTlsProtectCloud.node.js", "dist/nodes/Venafi/Datacenter/VenafiTlsProtectDatacenter.node.js", "dist/nodes/Vonage/Vonage.node.js", "dist/nodes/Wait/Wait.node.js", @@ -754,6 +756,7 @@ }, "dependencies": { "@kafkajs/confluent-schema-registry": "1.0.6", + "@types/js-nacl": "^1.3.0", "amqplib": "^0.8.0", "aws4": "^1.8.0", "basic-auth": "^2.0.1", @@ -773,6 +776,7 @@ "imap-simple": "^4.3.0", "isbot": "^3.3.4", "iso-639-1": "^2.1.3", + "js-nacl": "^1.4.0", "jsonwebtoken": "^8.5.1", "kafkajs": "^1.14.0", "lodash.get": "^4.4.2", From 694f1ba4f5780b2e9821db52e579883bbc289df4 Mon Sep 17 00:00:00 2001 From: Jonathan Bennetts Date: Fri, 7 Oct 2022 18:10:28 +0100 Subject: [PATCH 551/609] fix(Github Trigger Node): Fix issue with trigger not always activating (#4284) --- packages/nodes-base/nodes/Github/GithubTrigger.node.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nodes-base/nodes/Github/GithubTrigger.node.ts b/packages/nodes-base/nodes/Github/GithubTrigger.node.ts index 13ae1d960e7..1d059160d9b 100644 --- a/packages/nodes-base/nodes/Github/GithubTrigger.node.ts +++ b/packages/nodes-base/nodes/Github/GithubTrigger.node.ts @@ -363,7 +363,7 @@ export class GithubTrigger implements INodeType { try { await githubApiRequest.call(this, 'GET', endpoint, {}); } catch (error) { - if (error.httpCode === '404') { + if (error.cause.httpCode === '404') { // Webhook does not exist delete webhookData.webhookId; delete webhookData.webhookEvents; @@ -412,7 +412,7 @@ export class GithubTrigger implements INodeType { try { responseData = await githubApiRequest.call(this, 'POST', endpoint, body); } catch (error) { - if (error.httpCode === '422') { + if (error.cause.httpCode === '422') { // Webhook exists already // Get the data of the already registered webhook From 9407fddd21295b7bdf2757736b69b046a02e798c Mon Sep 17 00:00:00 2001 From: Stratos Theodorou Date: Fri, 7 Oct 2022 20:15:11 +0300 Subject: [PATCH 552/609] feat(Crypto Node): Add SHA3 support (#4285) Added SHA3-256, SHA3-384 and SHA3-512 algorithm support for hash and hmac actions. --- .../nodes-base/nodes/Crypto/Crypto.node.ts | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/packages/nodes-base/nodes/Crypto/Crypto.node.ts b/packages/nodes-base/nodes/Crypto/Crypto.node.ts index 72c03e1b0f1..32ffb2647ea 100644 --- a/packages/nodes-base/nodes/Crypto/Crypto.node.ts +++ b/packages/nodes-base/nodes/Crypto/Crypto.node.ts @@ -88,6 +88,18 @@ export class Crypto implements INodeType { name: 'SHA256', value: 'SHA256', }, + { + name: 'SHA3-256', + value: 'SHA3-256', + }, + { + name: 'SHA3-384', + value: 'SHA3-384', + }, + { + name: 'SHA3-512', + value: 'SHA3-512', + }, { name: 'SHA384', value: 'SHA384', @@ -167,6 +179,18 @@ export class Crypto implements INodeType { name: 'SHA256', value: 'SHA256', }, + { + name: 'SHA3-256', + value: 'SHA3-256', + }, + { + name: 'SHA3-384', + value: 'SHA3-384', + }, + { + name: 'SHA3-512', + value: 'SHA3-512', + }, { name: 'SHA384', value: 'SHA384', From 9b042c4923bc0ac6dc4aca964c4a393ca68a78be Mon Sep 17 00:00:00 2001 From: Ricardo Espinoza Date: Sun, 9 Oct 2022 02:11:32 -0400 Subject: [PATCH 553/609] refactor(cli): Remove console.log in curl converted tests (no-changelog) (#4289) :fire: Remove console.log --- packages/cli/test/unit/CurlConverterHelper.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/cli/test/unit/CurlConverterHelper.test.ts b/packages/cli/test/unit/CurlConverterHelper.test.ts index 9725795a9df..d83bd19c198 100644 --- a/packages/cli/test/unit/CurlConverterHelper.test.ts +++ b/packages/cli/test/unit/CurlConverterHelper.test.ts @@ -48,7 +48,6 @@ describe('CurlConverterHelper', () => { test('Should parse binary request correctly', () => { const curl = `curl --location --request POST 'https://www.website.com' --header 'Content-Type: image/png' --data-binary '@/Users/image.png`; const parameters = toHttpNodeParameters(curl); - console.log(JSON.stringify(parameters, undefined, 2)); expect(parameters.url).toBe('https://www.website.com'); expect(parameters.method).toBe('POST'); expect(parameters.sendBody).toBe(true); From f40f6620c834282955031c1cf1a4c8d13a0fb018 Mon Sep 17 00:00:00 2001 From: Mutasem Aldmour <4711238+mutdmour@users.noreply.github.com> Date: Mon, 10 Oct 2022 10:00:54 +0200 Subject: [PATCH 554/609] fix(editor): fix binary data view bug (#4298) --- packages/editor-ui/src/components/RunData.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/editor-ui/src/components/RunData.vue b/packages/editor-ui/src/components/RunData.vue index d760236a064..08544b574e8 100644 --- a/packages/editor-ui/src/components/RunData.vue +++ b/packages/editor-ui/src/components/RunData.vue @@ -178,7 +178,7 @@ {{ $locale.baseText('nodeErrorView.inputPanel.previousNodeError.text') }} - +
@@ -1161,7 +1161,7 @@ export default mixins( } } -.errorDisplay { +.dataDisplay { position: absolute; top: 0; left: 0; From 486a30a1525f30226a25379a7958b9c13e3215a2 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Mon, 10 Oct 2022 08:32:30 +0000 Subject: [PATCH 555/609] =?UTF-8?q?:bookmark:=20Release=C2=A0n8n-workflow@?= =?UTF-8?q?0.119.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/workflow/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/workflow/package.json b/packages/workflow/package.json index f7d3a3796ae..67e4ef84962 100644 --- a/packages/workflow/package.json +++ b/packages/workflow/package.json @@ -1,6 +1,6 @@ { "name": "n8n-workflow", - "version": "0.118.0", + "version": "0.119.0", "description": "Workflow base code of n8n", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://n8n.io", From 80b9b937d8654e6f5abf05fd683bec8014cf1589 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Mon, 10 Oct 2022 08:32:38 +0000 Subject: [PATCH 556/609] :arrow_up: Set n8n-workflow@0.119.0 on n8n-core --- packages/core/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/package.json b/packages/core/package.json index 845da38d339..315738e09ca 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -52,7 +52,7 @@ "form-data": "^4.0.0", "lodash.get": "^4.4.2", "mime-types": "^2.1.27", - "n8n-workflow": "~0.118.0", + "n8n-workflow": "~0.119.0", "oauth-1.0a": "^2.2.6", "p-cancelable": "^2.0.0", "qs": "^6.10.1", From c1683677cb8aa6c9abf61110d2163aedd76b842e Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Mon, 10 Oct 2022 08:32:38 +0000 Subject: [PATCH 557/609] =?UTF-8?q?:bookmark:=20Release=C2=A0n8n-core@0.13?= =?UTF-8?q?7.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/package.json b/packages/core/package.json index 315738e09ca..311fc8f6e36 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "n8n-core", - "version": "0.136.0", + "version": "0.137.0", "description": "Core functionality of n8n", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://n8n.io", From 42b747ad876dfe197b951caad0c5d240e6a097f0 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Mon, 10 Oct 2022 08:32:45 +0000 Subject: [PATCH 558/609] :arrow_up: Set n8n-core@0.137.0 and n8n-workflow@0.119.0 on n8n-node-dev --- packages/node-dev/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/node-dev/package.json b/packages/node-dev/package.json index c10319cf42f..1d5f880b36d 100644 --- a/packages/node-dev/package.json +++ b/packages/node-dev/package.json @@ -60,8 +60,8 @@ "change-case": "^4.1.1", "fast-glob": "^3.2.5", "inquirer": "^7.0.1", - "n8n-core": "~0.136.0", - "n8n-workflow": "~0.118.0", + "n8n-core": "~0.137.0", + "n8n-workflow": "~0.119.0", "oauth-1.0a": "^2.2.6", "replace-in-file": "^6.0.0", "request": "^2.88.2", From a3f2777c664fec2f98e027afc6e5bedc9c2fa738 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Mon, 10 Oct 2022 08:32:45 +0000 Subject: [PATCH 559/609] =?UTF-8?q?:bookmark:=20Release=C2=A0n8n-node-dev@?= =?UTF-8?q?0.76.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/node-dev/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/node-dev/package.json b/packages/node-dev/package.json index 1d5f880b36d..84b1091e506 100644 --- a/packages/node-dev/package.json +++ b/packages/node-dev/package.json @@ -1,6 +1,6 @@ { "name": "n8n-node-dev", - "version": "0.75.0", + "version": "0.76.0", "description": "CLI to simplify n8n credentials/node development", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://n8n.io", From daf8132c35879302ccb8cdbff59947c7d90f808e Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Mon, 10 Oct 2022 08:32:53 +0000 Subject: [PATCH 560/609] :arrow_up: Set n8n-core@0.137.0 and n8n-workflow@0.119.0 on n8n-nodes-base --- packages/nodes-base/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index d31e3404622..f7513baa79b 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -749,7 +749,7 @@ "eslint-plugin-n8n-nodes-base": "^1.9.3", "gulp": "^4.0.0", "jest": "^27.4.7", - "n8n-workflow": "~0.118.0", + "n8n-workflow": "~0.119.0", "ts-jest": "^27.1.3", "tslint": "^6.1.2", "typescript": "~4.8.0" @@ -790,7 +790,7 @@ "mqtt": "4.2.6", "mssql": "^8.1.2", "mysql2": "~2.3.0", - "n8n-core": "~0.136.0", + "n8n-core": "~0.137.0", "node-html-markdown": "^1.1.3", "node-ssh": "^12.0.0", "nodemailer": "^6.7.1", From 7949a22b6438273b76573b2ac4e3d55329792cdb Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Mon, 10 Oct 2022 08:32:53 +0000 Subject: [PATCH 561/609] =?UTF-8?q?:bookmark:=20Release=C2=A0n8n-nodes-bas?= =?UTF-8?q?e@0.195.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/nodes-base/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index f7513baa79b..1080ddf8a2c 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -1,6 +1,6 @@ { "name": "n8n-nodes-base", - "version": "0.194.0", + "version": "0.195.0", "description": "Base nodes of n8n", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://n8n.io", From 6a232d38d5754ee8f6f9dd776b7de41338e8995d Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Mon, 10 Oct 2022 08:33:42 +0000 Subject: [PATCH 562/609] =?UTF-8?q?:bookmark:=20Release=C2=A0n8n-design-sy?= =?UTF-8?q?stem@0.37.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/design-system/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/design-system/package.json b/packages/design-system/package.json index 9689489a9a9..fa5c5d131c4 100644 --- a/packages/design-system/package.json +++ b/packages/design-system/package.json @@ -1,6 +1,6 @@ { "name": "n8n-design-system", - "version": "0.36.0", + "version": "0.37.0", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://n8n.io", "author": { From ff43de7cb4856672f44e524fb3beb9e292f0a950 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Mon, 10 Oct 2022 08:33:57 +0000 Subject: [PATCH 563/609] :arrow_up: Set n8n-design-system@0.37.0 and n8n-workflow@0.119.0 on n8n-editor-ui --- packages/editor-ui/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/editor-ui/package.json b/packages/editor-ui/package.json index 3481d4614a9..f4e003dc4aa 100644 --- a/packages/editor-ui/package.json +++ b/packages/editor-ui/package.json @@ -45,8 +45,8 @@ "lodash.set": "^4.3.2", "luxon": "^2.3.0", "monaco-editor": "^0.30.1", - "n8n-design-system": "~0.36.0", - "n8n-workflow": "~0.118.0", + "n8n-design-system": "~0.37.0", + "n8n-workflow": "~0.119.0", "normalize-wheel": "^1.0.1", "prismjs": "^1.17.1", "quill": "2.0.0-dev.4", From 6169530e306f7144394f3f5c845dd04b9a350866 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Mon, 10 Oct 2022 08:33:57 +0000 Subject: [PATCH 564/609] =?UTF-8?q?:bookmark:=20Release=C2=A0n8n-editor-ui?= =?UTF-8?q?@0.163.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/editor-ui/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor-ui/package.json b/packages/editor-ui/package.json index f4e003dc4aa..9cc58ff2154 100644 --- a/packages/editor-ui/package.json +++ b/packages/editor-ui/package.json @@ -1,6 +1,6 @@ { "name": "n8n-editor-ui", - "version": "0.162.0", + "version": "0.163.0", "description": "Workflow Editor UI for n8n", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://n8n.io", From 02e2f33c42fc8e688dfc0a10507e944f2a1e3621 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Mon, 10 Oct 2022 08:40:33 +0000 Subject: [PATCH 565/609] :arrow_up: Set n8n-core@0.137.0, n8n-nodes-base@0.195.0 and n8n-workflow@0.119.0 on n8n --- packages/cli/package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index 122db350098..4b2381aa719 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -147,10 +147,10 @@ "lodash.split": "^4.4.2", "lodash.unset": "^4.5.2", "mysql2": "~2.3.0", - "n8n-core": "~0.136.0", + "n8n-core": "~0.137.0", "n8n-editor-ui": "~0.162.0", - "n8n-nodes-base": "~0.194.0", - "n8n-workflow": "~0.118.0", + "n8n-nodes-base": "~0.195.0", + "n8n-workflow": "~0.119.0", "nodemailer": "^6.7.1", "oauth-1.0a": "^2.2.6", "open": "^7.0.0", From 3ee1faf610be6a89be34f928071b263aedb3419a Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Mon, 10 Oct 2022 08:40:33 +0000 Subject: [PATCH 566/609] =?UTF-8?q?:bookmark:=20Release=C2=A0n8n@0.197.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/cli/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index 4b2381aa719..8ca931b0f79 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "n8n", - "version": "0.196.0", + "version": "0.197.0", "description": "n8n Workflow Automation Tool", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://n8n.io", From 06e60b2d1b6b807a5b5c88c8548341e87704c187 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Mon, 10 Oct 2022 10:42:39 +0200 Subject: [PATCH 567/609] :books: Update CHANGELOG.md and main package.json to 0.197.0 --- CHANGELOG.md | 34 ++++++++++++++++++++++++++++++++++ package.json | 2 +- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 293681a255b..077e46ca00a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,37 @@ +# [0.197.0](https://github.com/n8n-io/n8n/compare/n8n@0.196.0...n8n@0.197.0) (2022-10-10) + + +### Bug Fixes + +* **cli:** Cache generated assets in user writable directory instead ([#4275](https://github.com/n8n-io/n8n/issues/4275)) ([e63eee2](https://github.com/n8n-io/n8n/commit/e63eee28e00ae01fe4db92ac1235d7be7f25b76d)) +* **core:** Fix excess run for pinned trigger in partial execution ([#4185](https://github.com/n8n-io/n8n/issues/4185)) ([a751fd3](https://github.com/n8n-io/n8n/commit/a751fd3ce762df99490889153d36029ff4cd00da)) +* **core:** Fix hooks URLs no longer added to `index.html` ([#4262](https://github.com/n8n-io/n8n/issues/4262)) ([cc2a2e4](https://github.com/n8n-io/n8n/commit/cc2a2e438b0dee703b40dab67b4770dc06c76a7e)) +* **editor:** Fix `pairedItem` in combination with pinned data ([#4257](https://github.com/n8n-io/n8n/issues/4257)) ([e30c78f](https://github.com/n8n-io/n8n/commit/e30c78febeac8bfcfbe5f1c4c13122594d8a518e)) +* **editor:** Fix binary data view bug ([#4298](https://github.com/n8n-io/n8n/issues/4298)) ([f40f662](https://github.com/n8n-io/n8n/commit/f40f6620c834282955031c1cf1a4c8d13a0fb018)) +* **Github Trigger Node:** Fix issue with trigger not always activating ([#4284](https://github.com/n8n-io/n8n/issues/4284)) ([694f1ba](https://github.com/n8n-io/n8n/commit/694f1ba4f5780b2e9821db52e579883bbc289df4)) +* **Microsoft Excel Node:** Fix issue with pagination when getting all items ([#4247](https://github.com/n8n-io/n8n/issues/4247)) ([1067ec0](https://github.com/n8n-io/n8n/commit/1067ec0f5bd8e57650ccd9924e01fc52fbf0c43c)) +* **Microsoft ToDo Node:** Fix pagination issue when getting all items ([#4222](https://github.com/n8n-io/n8n/issues/4222)) ([4595b54](https://github.com/n8n-io/n8n/commit/4595b54e562c50c48bdfe8049cb170196713cc8b)) + + +### Features + +* **AWS Certificate Manager:** Add AWS Certificate Manager node ([#4263](https://github.com/n8n-io/n8n/issues/4263)) ([9b3f30d](https://github.com/n8n-io/n8n/commit/9b3f30d584901e7dc5fa87854e72f438f2557665)) +* **AWS Elastic Load Balancer Node:** Add Elastic Load Balancer node ([#4264](https://github.com/n8n-io/n8n/issues/4264)) ([fac6efb](https://github.com/n8n-io/n8n/commit/fac6efbb4158aa713bf5472d27b6fe341db8047d)) +* **Citrix ADC:** Add Citrix ADC node ([#4274](https://github.com/n8n-io/n8n/issues/4274)) ([7abc7e6](https://github.com/n8n-io/n8n/commit/7abc7e64082b60fa48f99f4b1f41d176fbb6d6ad)) +* **Cloudflare Node:** Add Cloudflare node ([#4271](https://github.com/n8n-io/n8n/issues/4271)) ([94a02c6](https://github.com/n8n-io/n8n/commit/94a02c64928205c441af5515739fe8eab7160b33)) +* **core:** Improve light versioning support in declarative node design ([#4254](https://github.com/n8n-io/n8n/issues/4254)) ([1b320cd](https://github.com/n8n-io/n8n/commit/1b320cd8c9b1e00257c03f92a175e3c9ab9f8030)) +* **Crypto Node:** Add SHA3 support ([#4285](https://github.com/n8n-io/n8n/issues/4285)) ([9407fdd](https://github.com/n8n-io/n8n/commit/9407fddd21295b7bdf2757736b69b046a02e798c)) +* **editor-ui:** JSON mapping ([#4270](https://github.com/n8n-io/n8n/issues/4270)) ([19e333e](https://github.com/n8n-io/n8n/commit/19e333e6602648feacd80277e170d8af38ce06c4)), closes [#4152](https://github.com/n8n-io/n8n/issues/4152) [#4158](https://github.com/n8n-io/n8n/issues/4158) [#4227](https://github.com/n8n-io/n8n/issues/4227) [#4250](https://github.com/n8n-io/n8n/issues/4250) [#4260](https://github.com/n8n-io/n8n/issues/4260) [#4273](https://github.com/n8n-io/n8n/issues/4273) +* **Venafi TLS Protect Cloud:** Add Venafi TLS Protect Cloud ([#4253](https://github.com/n8n-io/n8n/issues/4253)) ([d36e920](https://github.com/n8n-io/n8n/commit/d36e920997d55957385e4ab4d6734639a4c28648)) +* **Venafi TLS Protect Datacenter:** Add Venafi TLS Protect Datacenter node ([#4255](https://github.com/n8n-io/n8n/issues/4255)) ([a14110e](https://github.com/n8n-io/n8n/commit/a14110e663caca8e886312a116805c41020ba812)) + + +### Performance Improvements + +* **tooling:** Upgrade to TypeScript 4.8 ([#4207](https://github.com/n8n-io/n8n/issues/4207)) ([9089dbe](https://github.com/n8n-io/n8n/commit/9089dbe94220f1789d2cea74608352a070e09bac)) + + + # [0.196.0](https://github.com/n8n-io/n8n/compare/n8n@0.195.5...n8n@0.196.0) (2022-09-30) diff --git a/package.json b/package.json index c7eb82b1987..2a23cbb7b0d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "n8n", - "version": "0.196.0", + "version": "0.197.0", "private": true, "homepage": "https://n8n.io", "scripts": { From 561245b6e0b65fcd9baf6fa2765b7954d48f9ea0 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Mon, 10 Oct 2022 11:20:16 +0200 Subject: [PATCH 568/609] :books: Improve Changelog --- CHANGELOG.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 077e46ca00a..7f8125f2df6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,6 @@ * **core:** Fix excess run for pinned trigger in partial execution ([#4185](https://github.com/n8n-io/n8n/issues/4185)) ([a751fd3](https://github.com/n8n-io/n8n/commit/a751fd3ce762df99490889153d36029ff4cd00da)) * **core:** Fix hooks URLs no longer added to `index.html` ([#4262](https://github.com/n8n-io/n8n/issues/4262)) ([cc2a2e4](https://github.com/n8n-io/n8n/commit/cc2a2e438b0dee703b40dab67b4770dc06c76a7e)) * **editor:** Fix `pairedItem` in combination with pinned data ([#4257](https://github.com/n8n-io/n8n/issues/4257)) ([e30c78f](https://github.com/n8n-io/n8n/commit/e30c78febeac8bfcfbe5f1c4c13122594d8a518e)) -* **editor:** Fix binary data view bug ([#4298](https://github.com/n8n-io/n8n/issues/4298)) ([f40f662](https://github.com/n8n-io/n8n/commit/f40f6620c834282955031c1cf1a4c8d13a0fb018)) * **Github Trigger Node:** Fix issue with trigger not always activating ([#4284](https://github.com/n8n-io/n8n/issues/4284)) ([694f1ba](https://github.com/n8n-io/n8n/commit/694f1ba4f5780b2e9821db52e579883bbc289df4)) * **Microsoft Excel Node:** Fix issue with pagination when getting all items ([#4247](https://github.com/n8n-io/n8n/issues/4247)) ([1067ec0](https://github.com/n8n-io/n8n/commit/1067ec0f5bd8e57650ccd9924e01fc52fbf0c43c)) * **Microsoft ToDo Node:** Fix pagination issue when getting all items ([#4222](https://github.com/n8n-io/n8n/issues/4222)) ([4595b54](https://github.com/n8n-io/n8n/commit/4595b54e562c50c48bdfe8049cb170196713cc8b)) @@ -15,15 +14,15 @@ ### Features -* **AWS Certificate Manager:** Add AWS Certificate Manager node ([#4263](https://github.com/n8n-io/n8n/issues/4263)) ([9b3f30d](https://github.com/n8n-io/n8n/commit/9b3f30d584901e7dc5fa87854e72f438f2557665)) +* **AWS Certificate Manager Node:** Add AWS Certificate Manager node ([#4263](https://github.com/n8n-io/n8n/issues/4263)) ([9b3f30d](https://github.com/n8n-io/n8n/commit/9b3f30d584901e7dc5fa87854e72f438f2557665)) * **AWS Elastic Load Balancer Node:** Add Elastic Load Balancer node ([#4264](https://github.com/n8n-io/n8n/issues/4264)) ([fac6efb](https://github.com/n8n-io/n8n/commit/fac6efbb4158aa713bf5472d27b6fe341db8047d)) -* **Citrix ADC:** Add Citrix ADC node ([#4274](https://github.com/n8n-io/n8n/issues/4274)) ([7abc7e6](https://github.com/n8n-io/n8n/commit/7abc7e64082b60fa48f99f4b1f41d176fbb6d6ad)) +* **Citrix ADC Node:** Add Citrix ADC node ([#4274](https://github.com/n8n-io/n8n/issues/4274)) ([7abc7e6](https://github.com/n8n-io/n8n/commit/7abc7e64082b60fa48f99f4b1f41d176fbb6d6ad)) * **Cloudflare Node:** Add Cloudflare node ([#4271](https://github.com/n8n-io/n8n/issues/4271)) ([94a02c6](https://github.com/n8n-io/n8n/commit/94a02c64928205c441af5515739fe8eab7160b33)) * **core:** Improve light versioning support in declarative node design ([#4254](https://github.com/n8n-io/n8n/issues/4254)) ([1b320cd](https://github.com/n8n-io/n8n/commit/1b320cd8c9b1e00257c03f92a175e3c9ab9f8030)) * **Crypto Node:** Add SHA3 support ([#4285](https://github.com/n8n-io/n8n/issues/4285)) ([9407fdd](https://github.com/n8n-io/n8n/commit/9407fddd21295b7bdf2757736b69b046a02e798c)) -* **editor-ui:** JSON mapping ([#4270](https://github.com/n8n-io/n8n/issues/4270)) ([19e333e](https://github.com/n8n-io/n8n/commit/19e333e6602648feacd80277e170d8af38ce06c4)), closes [#4152](https://github.com/n8n-io/n8n/issues/4152) [#4158](https://github.com/n8n-io/n8n/issues/4158) [#4227](https://github.com/n8n-io/n8n/issues/4227) [#4250](https://github.com/n8n-io/n8n/issues/4250) [#4260](https://github.com/n8n-io/n8n/issues/4260) [#4273](https://github.com/n8n-io/n8n/issues/4273) -* **Venafi TLS Protect Cloud:** Add Venafi TLS Protect Cloud ([#4253](https://github.com/n8n-io/n8n/issues/4253)) ([d36e920](https://github.com/n8n-io/n8n/commit/d36e920997d55957385e4ab4d6734639a4c28648)) -* **Venafi TLS Protect Datacenter:** Add Venafi TLS Protect Datacenter node ([#4255](https://github.com/n8n-io/n8n/issues/4255)) ([a14110e](https://github.com/n8n-io/n8n/commit/a14110e663caca8e886312a116805c41020ba812)) +* **editor:** JSON mapping ([#4270](https://github.com/n8n-io/n8n/issues/4270)) ([19e333e](https://github.com/n8n-io/n8n/commit/19e333e6602648feacd80277e170d8af38ce06c4)) +* **Venafi TLS Protect Cloud Node:** Add Venafi TLS Protect Cloud ([#4253](https://github.com/n8n-io/n8n/issues/4253)) ([d36e920](https://github.com/n8n-io/n8n/commit/d36e920997d55957385e4ab4d6734639a4c28648)) +* **Venafi TLS Protect Datacenter Node:** Add Venafi TLS Protect Datacenter node ([#4255](https://github.com/n8n-io/n8n/issues/4255)) ([a14110e](https://github.com/n8n-io/n8n/commit/a14110e663caca8e886312a116805c41020ba812)) ### Performance Improvements From 845d1f8bd9763e9b886ac70c7ccbd37ff1c24b43 Mon Sep 17 00:00:00 2001 From: Mutasem Aldmour <4711238+mutdmour@users.noreply.github.com> Date: Mon, 10 Oct 2022 13:07:12 +0200 Subject: [PATCH 569/609] fix(editor): fix resource locator width for trigger nodes (#4302) --- .../src/components/ResourceLocator/ResourceLocator.vue | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/editor-ui/src/components/ResourceLocator/ResourceLocator.vue b/packages/editor-ui/src/components/ResourceLocator/ResourceLocator.vue index d24aee18109..fa44682c847 100644 --- a/packages/editor-ui/src/components/ResourceLocator/ResourceLocator.vue +++ b/packages/editor-ui/src/components/ResourceLocator/ResourceLocator.vue @@ -427,9 +427,11 @@ export default mixins(debounceHelper, workflowHelpers, nodeHelpers).extend({ }, mounted() { this.$on('refreshList', this.refreshList); - this.setWidth(); window.addEventListener('resize', this.setWidth); this.mainPanelMutationSubscription = this.$store.subscribe(this.setWidthOnMainPanelResize); + setTimeout(() => { + this.setWidth(); + }, 0); }, beforeDestroy() { // Unsubscribe From ec9adcb7b4a12748ff2bac815f671321ad4f5dbc Mon Sep 17 00:00:00 2001 From: Deborah Date: Mon, 10 Oct 2022 13:11:32 +0100 Subject: [PATCH 570/609] docs(nodes): fix credentials docs link (#4305) --- .../Venafi/Datacenter/VenafiTlsProtectDatacenter.node.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nodes-base/nodes/Venafi/Datacenter/VenafiTlsProtectDatacenter.node.json b/packages/nodes-base/nodes/Venafi/Datacenter/VenafiTlsProtectDatacenter.node.json index 459bcd2814d..b9e14369494 100644 --- a/packages/nodes-base/nodes/Venafi/Datacenter/VenafiTlsProtectDatacenter.node.json +++ b/packages/nodes-base/nodes/Venafi/Datacenter/VenafiTlsProtectDatacenter.node.json @@ -6,7 +6,7 @@ "resources": { "credentialDocumentation": [ { - "url": "https://docs.n8n.io/credentials/venafiTlsProtectDatacenter" + "url": "https://docs.n8n.io/integrations/builtin/credentials/venafiTlsProtectDatacenter/" } ], "primaryDocumentation": [ From b51f91444dcb388cd21c9e3cb72c94b744270835 Mon Sep 17 00:00:00 2001 From: Deborah Date: Mon, 10 Oct 2022 13:11:53 +0100 Subject: [PATCH 571/609] docs(nodes): fix the credentials docs link (#4304) Update VenafiTlsProtectCloud.node.json Correct credentials docs link --- .../nodes/Venafi/ProtectCloud/VenafiTlsProtectCloud.node.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nodes-base/nodes/Venafi/ProtectCloud/VenafiTlsProtectCloud.node.json b/packages/nodes-base/nodes/Venafi/ProtectCloud/VenafiTlsProtectCloud.node.json index 8aaa7e1d1f8..a1fc4fc0a2e 100644 --- a/packages/nodes-base/nodes/Venafi/ProtectCloud/VenafiTlsProtectCloud.node.json +++ b/packages/nodes-base/nodes/Venafi/ProtectCloud/VenafiTlsProtectCloud.node.json @@ -6,7 +6,7 @@ "resources": { "credentialDocumentation": [ { - "url": "https://docs.n8n.io/credentials/venafiTlsProtectCloud" + "url": "https://docs.n8n.io/integrations/builtin/credentials/venafiTlsProtectCloud/" } ], "primaryDocumentation": [ From 7dd28207c1f082a1cacf066e92d96991339bc143 Mon Sep 17 00:00:00 2001 From: Deborah Date: Mon, 10 Oct 2022 13:12:05 +0100 Subject: [PATCH 572/609] docs(node): update CitrixAdc.node.json to use correct docs URLs (#4300) Update CitrixAdc.node.json --- packages/nodes-base/nodes/Citrix/ADC/CitrixAdc.node.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nodes-base/nodes/Citrix/ADC/CitrixAdc.node.json b/packages/nodes-base/nodes/Citrix/ADC/CitrixAdc.node.json index 482c858b1dc..8239059cde5 100644 --- a/packages/nodes-base/nodes/Citrix/ADC/CitrixAdc.node.json +++ b/packages/nodes-base/nodes/Citrix/ADC/CitrixAdc.node.json @@ -6,12 +6,12 @@ "resources": { "credentialDocumentation": [ { - "url": "https://docs.n8n.io/credentials/citrixAdc" + "url": "https://docs.n8n.io/integrations/builtin/credentials/citrixAdc/" } ], "primaryDocumentation": [ { - "url": "https://docs.n8n.io/nodes/n8n-nodes-base.citrixAdc/" + "url": "https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.citrixAdc/" } ] } From 9295841983ebd0e573dfa76246d9eb89149a8bb1 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Mon, 10 Oct 2022 12:25:50 +0000 Subject: [PATCH 573/609] =?UTF-8?q?:bookmark:=20Release=C2=A0n8n-nodes-bas?= =?UTF-8?q?e@0.195.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/cli/package.json | 2 +- packages/nodes-base/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index 8ca931b0f79..2f3ddd823a4 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -148,7 +148,7 @@ "lodash.unset": "^4.5.2", "mysql2": "~2.3.0", "n8n-core": "~0.137.0", - "n8n-editor-ui": "~0.162.0", + "n8n-editor-ui": "~0.163.0", "n8n-nodes-base": "~0.195.0", "n8n-workflow": "~0.119.0", "nodemailer": "^6.7.1", diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index 1080ddf8a2c..51aee202af8 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -1,6 +1,6 @@ { "name": "n8n-nodes-base", - "version": "0.195.0", + "version": "0.195.1", "description": "Base nodes of n8n", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://n8n.io", From dd58771fc34c9290936d4c93060df2cf32ce77ce Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Mon, 10 Oct 2022 12:26:42 +0000 Subject: [PATCH 574/609] =?UTF-8?q?:bookmark:=20Release=C2=A0n8n-editor-ui?= =?UTF-8?q?@0.163.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/editor-ui/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor-ui/package.json b/packages/editor-ui/package.json index 9cc58ff2154..61db5f9129a 100644 --- a/packages/editor-ui/package.json +++ b/packages/editor-ui/package.json @@ -1,6 +1,6 @@ { "name": "n8n-editor-ui", - "version": "0.163.0", + "version": "0.163.1", "description": "Workflow Editor UI for n8n", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://n8n.io", From ca38861bda6ffc9e368587bf605738b56d2b5215 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Mon, 10 Oct 2022 12:28:13 +0000 Subject: [PATCH 575/609] :arrow_up: Set n8n-editor-ui@0.163.1 and n8n-nodes-base@0.195.1 on n8n --- packages/cli/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index 2f3ddd823a4..5075cc95ed2 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -148,8 +148,8 @@ "lodash.unset": "^4.5.2", "mysql2": "~2.3.0", "n8n-core": "~0.137.0", - "n8n-editor-ui": "~0.163.0", - "n8n-nodes-base": "~0.195.0", + "n8n-editor-ui": "~0.163.1", + "n8n-nodes-base": "~0.195.1", "n8n-workflow": "~0.119.0", "nodemailer": "^6.7.1", "oauth-1.0a": "^2.2.6", From 7786a173d355fec2dcb737e31c5857446b54c052 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Mon, 10 Oct 2022 12:28:15 +0000 Subject: [PATCH 576/609] =?UTF-8?q?:bookmark:=20Release=C2=A0n8n@0.197.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/cli/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index 5075cc95ed2..fc1568b565e 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "n8n", - "version": "0.197.0", + "version": "0.197.1", "description": "n8n Workflow Automation Tool", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://n8n.io", From b6e4f68bb03903e8c462a7e9368dc547e4018491 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Mon, 10 Oct 2022 14:32:04 +0200 Subject: [PATCH 577/609] :books: Update CHANGELOG.md and main package.json to 0.197.1 --- CHANGELOG.md | 8 ++++++++ package.json | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f8125f2df6..a135c2578c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## [0.197.1](https://github.com/n8n-io/n8n/compare/n8n@0.197.0...n8n@0.197.1) (2022-10-10) + + +### Bug Fixes + +* **editor:** Fix resource locator width for trigger nodes ([#4302](https://github.com/n8n-io/n8n/issues/4302)) ([845d1f8](https://github.com/n8n-io/n8n/commit/845d1f8bd9763e9b886ac70c7ccbd37ff1c24b43)) + + # [0.197.0](https://github.com/n8n-io/n8n/compare/n8n@0.196.0...n8n@0.197.0) (2022-10-10) diff --git a/package.json b/package.json index 2a23cbb7b0d..bf67b864d35 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "n8n", - "version": "0.197.0", + "version": "0.197.1", "private": true, "homepage": "https://n8n.io", "scripts": { From fdbc11a288f9fe9aac36017366b5817a05f4fbbf Mon Sep 17 00:00:00 2001 From: Csaba Tuncsik Date: Mon, 10 Oct 2022 17:23:22 +0200 Subject: [PATCH 578/609] fix(editor): change horizontal scrollbar rendering in various places (#4282) * fix(editor-ui): workflow templates carousel scroll * fix(design-system): prevent visible scrollbar on Tags * fix(editor): add types to component prop * fix(editor): add types to component prop --- .../design-system/src/components/N8nTags/Tags.vue | 11 +++++++++++ .../src/components/CollectionsCarousel.vue | 15 ++++----------- .../editor-ui/src/components/TemplateDetails.vue | 6 +++--- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/packages/design-system/src/components/N8nTags/Tags.vue b/packages/design-system/src/components/N8nTags/Tags.vue index 4e690c2b7de..52a3b304cc1 100644 --- a/packages/design-system/src/components/N8nTags/Tags.vue +++ b/packages/design-system/src/components/N8nTags/Tags.vue @@ -25,6 +25,17 @@ export default Vue.extend({ .tags { display: flex; flex-wrap: wrap; + overflow-x: scroll; + + /* Hide scrollbar for Chrome, Safari and Opera */ + &::-webkit-scrollbar { + display: none; + } + + /* Hide scrollbar for IE, Edge and Firefox */ + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ + * { margin: 0 var(--spacing-4xs) var(--spacing-4xs) 0; diff --git a/packages/editor-ui/src/components/CollectionsCarousel.vue b/packages/editor-ui/src/components/CollectionsCarousel.vue index 50228035708..90661200137 100644 --- a/packages/editor-ui/src/components/CollectionsCarousel.vue +++ b/packages/editor-ui/src/components/CollectionsCarousel.vue @@ -19,6 +19,8 @@ diff --git a/packages/design-system/src/components/N8nMenuItem/MenuItem.stories.ts b/packages/design-system/src/components/N8nMenuItem/MenuItem.stories.ts new file mode 100644 index 00000000000..7d185ae472d --- /dev/null +++ b/packages/design-system/src/components/N8nMenuItem/MenuItem.stories.ts @@ -0,0 +1,79 @@ +import N8nMenuItem from "."; +import ElMenu from 'element-ui/lib/menu'; +import { StoryFn } from '@storybook/vue'; + +export default { + title: 'Atoms/MenuItem', + component: N8nMenuItem, +}; + +const template: StoryFn = (args, { argTypes }) => ({ + props: Object.keys(argTypes), + components: { + ElMenu, // eslint-disable-line @typescript-eslint/no-unsafe-assignment + N8nMenuItem , + }, + template: ` +
+ + + +
+ `, +}); + +export const defaultMenuItem = template.bind({}); +defaultMenuItem.args = { + item: { + id: 'workflows', + icon: 'heart', + label: 'Workflows', + }, +}; + +export const compact = template.bind({}); +compact.args = { + item: { + id: 'compact', + icon: 'ice-cream', + label: 'Click here', + }, + compact: true, +}; + +export const link = template.bind({}); +link.args = { + item: { + id: 'website', + icon: 'globe', + label: 'Website', + type: 'link', + properties: { + href: 'https://www.n8n.io', + newWindow: true, + }, + }, +}; + +export const withChildren = template.bind({}); +withChildren.args = { + item: { + id: 'help', + icon: 'question', + label: 'Help', + children: [ + { icon: 'info', label: 'About n8n', id: 'about' }, + { icon: 'book', label: 'Documentation', id: 'docs' }, + { + id: 'quickstart', + icon: 'video', + label: 'Quickstart', + type: 'link', + properties: { + href: 'https://www.youtube.com/watch?v=RpjQTGKm-ok', + newWindow: true, + }, + }, + ], + }, +}; diff --git a/packages/design-system/src/components/N8nMenuItem/MenuItem.vue b/packages/design-system/src/components/N8nMenuItem/MenuItem.vue index 0960fc3940b..7affae987f8 100644 --- a/packages/design-system/src/components/N8nMenuItem/MenuItem.vue +++ b/packages/design-system/src/components/N8nMenuItem/MenuItem.vue @@ -1,7 +1,272 @@ + + + + diff --git a/packages/design-system/src/types/index.ts b/packages/design-system/src/types/index.ts index a9602f5874b..4e7d31c6e68 100644 --- a/packages/design-system/src/types/index.ts +++ b/packages/design-system/src/types/index.ts @@ -1,3 +1,4 @@ export * from './form'; export * from './user'; +export * from './menu'; export * from './button'; diff --git a/packages/design-system/src/types/menu.ts b/packages/design-system/src/types/menu.ts new file mode 100644 index 00000000000..b66b2f8c504 --- /dev/null +++ b/packages/design-system/src/types/menu.ts @@ -0,0 +1,21 @@ +export type IMenuItem = { + id: string; + label: string; + icon?: string; + customIconSize?: 'medium' | 'small'; + available?: boolean; + position?: 'top' | 'bottom'; + type?: 'default' | 'link'; + properties?: ILinkMenuItemProperties; + // For router menus populate only one of those arrays: + // If menu item can be activated on certain route names (easy mode) + activateOnRouteNames?: string[], + // For more specific matching, we can use paths + activateOnRoutePaths?: string[], + children?: IMenuItem[], +}; + +export type ILinkMenuItemProperties = { + href: string; + newWindow?: boolean; +}; diff --git a/packages/editor-ui/src/Interface.ts b/packages/editor-ui/src/Interface.ts index c38766fd29f..747435c9acb 100644 --- a/packages/editor-ui/src/Interface.ts +++ b/packages/editor-ui/src/Interface.ts @@ -754,23 +754,6 @@ export interface ITimeoutHMS { export type WorkflowTitleStatus = 'EXECUTING' | 'IDLE' | 'ERROR'; -export type MenuItemType = 'link'; -export type MenuItemPosition = 'top' | 'bottom'; - -export interface IMenuItem { - id: string; - type: MenuItemType; - position?: MenuItemPosition; - properties: ILinkMenuItemProperties; -} - -export interface ILinkMenuItemProperties { - title: string; - icon: string; - href: string; - newWindow?: boolean; -} - export interface ISubcategoryItemProps { subcategory: string; description: string; diff --git a/packages/editor-ui/src/components/CredentialEdit/CredentialEdit.vue b/packages/editor-ui/src/components/CredentialEdit/CredentialEdit.vue index 851eec8503d..4a52a9cde71 100644 --- a/packages/editor-ui/src/components/CredentialEdit/CredentialEdit.vue +++ b/packages/editor-ui/src/components/CredentialEdit/CredentialEdit.vue @@ -49,34 +49,7 @@ - - diff --git a/packages/editor-ui/src/components/MenuItemsIterator.vue b/packages/editor-ui/src/components/MenuItemsIterator.vue deleted file mode 100644 index eaee86c78f9..00000000000 --- a/packages/editor-ui/src/components/MenuItemsIterator.vue +++ /dev/null @@ -1,49 +0,0 @@ - - - diff --git a/packages/editor-ui/src/components/SettingsSidebar.vue b/packages/editor-ui/src/components/SettingsSidebar.vue index 9ade642415d..35ccc86cefc 100644 --- a/packages/editor-ui/src/components/SettingsSidebar.vue +++ b/packages/editor-ui/src/components/SettingsSidebar.vue @@ -1,53 +1,22 @@ @@ -59,6 +28,8 @@ import { userHelpers } from './mixins/userHelpers'; import { pushConnection } from "@/components/mixins/pushConnection"; import { IFakeDoor } from '@/Interface'; import GiftNotificationIcon from './GiftNotificationIcon.vue'; +import { IMenuItem } from 'n8n-design-system'; +import { BaseTextKey } from '@/plugins/i18n'; export default mixins( userHelpers, @@ -73,6 +44,64 @@ export default mixins( settingsFakeDoorFeatures(): IFakeDoor[] { return this.$store.getters['ui/getFakeDoorByLocation']('settings'); }, + sidebarMenuItems(): IMenuItem[] { + + const menuItems: IMenuItem[] = [ + { + id: 'settings-personal', + icon: 'user-circle', + label: this.$locale.baseText('settings.personal'), + position: 'top', + available: this.canAccessPersonalSettings(), + activateOnRouteNames: [ VIEWS.PERSONAL_SETTINGS ], + }, + { + id: 'settings-users', + icon: 'user-friends', + label: this.$locale.baseText('settings.users'), + position: 'top', + available: this.canAccessUsersSettings(), + activateOnRouteNames: [ VIEWS.USERS_SETTINGS ], + }, + { + id: 'settings-api', + icon: 'plug', + label: this.$locale.baseText('settings.n8napi'), + position: 'top', + available: this.canAccessApiSettings(), + activateOnRouteNames: [ VIEWS.API_SETTINGS ], + }, + ]; + + for (const item of this.settingsFakeDoorFeatures) { + if (item.uiLocations.includes('settings')) { + menuItems.push({ + id: item.id, + icon: item.icon || 'question', + label: this.$locale.baseText(item.featureName as BaseTextKey), + position: 'top', + available: true, + activateOnRoutePaths: [ `/settings/coming-soon/${item.id}` ], + }); + } + } + + menuItems.push( + { + id: 'settings-community-nodes', + icon: 'cube', + label: this.$locale.baseText('settings.communityNodes'), + position: 'top', + available: this.canAccessCommunityNodes(), + activateOnRouteNames: [ VIEWS.COMMUNITY_NODES ], + }, + ); + + return menuItems; + }, + }, + mounted() { + this.pushConnect(); }, methods: { canAccessPersonalSettings(): boolean { @@ -96,83 +125,60 @@ export default mixins( openUpdatesPanel() { this.$store.dispatch('ui/openModal', VERSIONS_MODAL_KEY); }, - }, - mounted() { - this.pushConnect(); + async handleSelect (key: string) { + switch (key) { + case 'settings-personal': + if (this.$router.currentRoute.name !== VIEWS.PERSONAL_SETTINGS) { + this.$router.push({ name: VIEWS.PERSONAL_SETTINGS }); + } + break; + case 'settings-users': + if (this.$router.currentRoute.name !== VIEWS.USERS_SETTINGS) { + this.$router.push({ name: VIEWS.USERS_SETTINGS }); + } + break; + case 'settings-api': + if (this.$router.currentRoute.name !== VIEWS.API_SETTINGS) { + this.$router.push({ name: VIEWS.API_SETTINGS }); + } + break; + case 'environments': + case 'logging': + this.$router.push({ name: VIEWS.FAKE_DOOR, params: { featureId: key } }).catch(() => {}); + break; + case 'settings-community-nodes': + if (this.$router.currentRoute.name !== VIEWS.COMMUNITY_NODES) { + this.$router.push({ name: VIEWS.COMMUNITY_NODES }); + } + break; + default: + break; + } + }, }, }); From 13f52a25446438da8bae47af0633bc226b8f4d4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Ovejero?= Date: Mon, 10 Oct 2022 19:50:26 +0200 Subject: [PATCH 581/609] ci: revert sorting CI steps by length (no-changelog) (#4306) :rewind: Revert "perf(ci): Sort CI steps by length (#4243)" This reverts commit d47ff48fb633cb93cc1df2be06f9608f4f23c14a. --- .github/workflows/ci-master.yml | 6 +++--- .github/workflows/ci-pull-requests.yml | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci-master.yml b/.github/workflows/ci-master.yml index d1da655d9d3..f340184a82b 100644 --- a/.github/workflows/ci-master.yml +++ b/.github/workflows/ci-master.yml @@ -27,11 +27,11 @@ jobs: - name: Install npm and dependencies run: npm install -g npm@latest && npm install - - name: Lint - run: npm run lint - - name: Build run: npm run build --if-present - name: Test run: npm run test + + - name: Lint + run: npm run lint diff --git a/.github/workflows/ci-pull-requests.yml b/.github/workflows/ci-pull-requests.yml index e44c25c0d7b..3be4f949faf 100644 --- a/.github/workflows/ci-pull-requests.yml +++ b/.github/workflows/ci-pull-requests.yml @@ -24,6 +24,12 @@ jobs: - name: Install npm and dependencies run: npm install -g npm@latest && npm install + - name: Build + run: npm run build --if-present + + - name: Test + run: npm run test + - name: Fetch base branch for `git diff` run: git fetch origin ${{ github.event.pull_request.base.ref }}:${{ github.event.pull_request.base.ref }} @@ -31,9 +37,3 @@ jobs: env: ESLINT_PLUGIN_DIFF_COMMIT: ${{ github.event.pull_request.base.ref }} run: npm run lint - - - name: Build - run: npm run build --if-present - - - name: Test - run: npm run test From f914e6f4cb9964bd524a2a5fc432d4c69873246a Mon Sep 17 00:00:00 2001 From: Jonathan Bennetts Date: Tue, 11 Oct 2022 08:49:02 +0100 Subject: [PATCH 582/609] fix(TheHive Node): fix typo in severity name for alert updates (#4259) --- .../nodes-base/nodes/TheHive/descriptions/AlertDescription.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nodes-base/nodes/TheHive/descriptions/AlertDescription.ts b/packages/nodes-base/nodes/TheHive/descriptions/AlertDescription.ts index 642bb259da6..f2499af8de7 100644 --- a/packages/nodes-base/nodes/TheHive/descriptions/AlertDescription.ts +++ b/packages/nodes-base/nodes/TheHive/descriptions/AlertDescription.ts @@ -655,7 +655,7 @@ export const alertFields: INodeProperties[] = [ }, { displayName: 'Severity', - name: ' severity', + name: 'severity', type: 'options', options: [ { From a2a397e980d982a897546eea0ec33aa801cfb582 Mon Sep 17 00:00:00 2001 From: Jonathan Bennetts Date: Tue, 11 Oct 2022 08:49:25 +0100 Subject: [PATCH 583/609] fix(HubSpot Node): fix typo in deal search operator (#4278) --- packages/nodes-base/nodes/Hubspot/DealDescription.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nodes-base/nodes/Hubspot/DealDescription.ts b/packages/nodes-base/nodes/Hubspot/DealDescription.ts index efad2672c44..6cd325da406 100644 --- a/packages/nodes-base/nodes/Hubspot/DealDescription.ts +++ b/packages/nodes-base/nodes/Hubspot/DealDescription.ts @@ -617,7 +617,7 @@ export const dealFields: INodeProperties[] = [ options: [ { name: 'Contains Exactly', - value: 'CONSTAIN_TOKEN', + value: 'CONTAINS_TOKEN', }, { name: 'Equal', From aa6c786041d754bb795e3afd52e76c09541ffb63 Mon Sep 17 00:00:00 2001 From: Jonathan Bennetts Date: Tue, 11 Oct 2022 08:49:51 +0100 Subject: [PATCH 584/609] fix(HTTP Request Node): fix oauth credentials not working properly for some predefined credentials (#4277) --- .../nodes/HttpRequest/GenericFunctions.ts | 64 ++++++++++++++++++- .../HttpRequest/V2/HttpRequestV2.node.ts | 23 +------ .../HttpRequest/V3/HttpRequestV3.node.ts | 25 +------- 3 files changed, 68 insertions(+), 44 deletions(-) diff --git a/packages/nodes-base/nodes/HttpRequest/GenericFunctions.ts b/packages/nodes-base/nodes/HttpRequest/GenericFunctions.ts index 067ce5da357..7b4a9edd14a 100644 --- a/packages/nodes-base/nodes/HttpRequest/GenericFunctions.ts +++ b/packages/nodes-base/nodes/HttpRequest/GenericFunctions.ts @@ -1,4 +1,4 @@ -import { INodeExecutionData } from 'n8n-workflow'; +import { INodeExecutionData, IOAuth2Options } from 'n8n-workflow'; export const replaceNullValues = (item: INodeExecutionData) => { if (item.json === null) { @@ -6,3 +6,65 @@ export const replaceNullValues = (item: INodeExecutionData) => { } return item; }; + +export const getOAuth2AdditionalParameters = (nodeCredentialType: string) => { + const oAuth2Options: { [credentialType: string]: IOAuth2Options } = { + bitlyOAuth2Api: { + tokenType: 'Bearer', + }, + boxOAuth2Api: { + includeCredentialsOnRefreshOnBody: true, + }, + ciscoWebexOAuth2Api: { + tokenType: 'Bearer', + }, + clickUpOAuth2Api: { + keepBearer: false, + tokenType: 'Bearer', + }, + goToWebinarOAuth2Api: { + tokenExpiredStatusCode: 403, + }, + hubspotDeveloperApi: { + tokenType: 'Bearer', + includeCredentialsOnRefreshOnBody: true, + }, + hubspotOAuth2Api: { + tokenType: 'Bearer', + includeCredentialsOnRefreshOnBody: true, + }, + lineNotifyOAuth2Api: { + tokenType: 'Bearer', + }, + linkedInOAuth2Api: { + tokenType: 'Bearer', + }, + mailchimpOAuth2Api: { + tokenType: 'Bearer', + }, + mauticOAuth2Api: { + includeCredentialsOnRefreshOnBody: true, + }, + microsoftDynamicsOAuth2Api: { + property: 'id_token', + }, + philipsHueOAuth2Api: { + tokenType: 'Bearer', + }, + raindropOAuth2Api: { + includeCredentialsOnRefreshOnBody: true, + }, + shopifyOAuth2Api: { + tokenType: 'Bearer', + keyToIncludeInAccessTokenHeader: 'X-Shopify-Access-Token', + }, + slackOAuth2Api: { + tokenType: 'Bearer', + property: 'authed_user.access_token', + }, + stravaOAuth2Api: { + includeCredentialsOnRefreshOnBody: true, + }, + }; + return oAuth2Options[nodeCredentialType]; +}; diff --git a/packages/nodes-base/nodes/HttpRequest/V2/HttpRequestV2.node.ts b/packages/nodes-base/nodes/HttpRequest/V2/HttpRequestV2.node.ts index 27c2c6c8a4d..ad954e361a0 100644 --- a/packages/nodes-base/nodes/HttpRequest/V2/HttpRequestV2.node.ts +++ b/packages/nodes-base/nodes/HttpRequest/V2/HttpRequestV2.node.ts @@ -6,13 +6,12 @@ import { INodeType, INodeTypeBaseDescription, INodeTypeDescription, - IOAuth2Options, NodeApiError, NodeOperationError, } from 'n8n-workflow'; import { OptionsWithUri } from 'request'; -import { replaceNullValues } from '../GenericFunctions'; +import { getOAuth2AdditionalParameters, replaceNullValues } from '../GenericFunctions'; interface OptionData { name: string; @@ -1010,25 +1009,7 @@ export class HttpRequestV2 implements INodeType { requestPromises.push(request); } } else if (authentication === 'predefinedCredentialType' && nodeCredentialType) { - const oAuth2Options: { [credentialType: string]: IOAuth2Options } = { - clickUpOAuth2Api: { - keepBearer: false, - tokenType: 'Bearer', - }, - slackOAuth2Api: { - tokenType: 'Bearer', - property: 'authed_user.access_token', - }, - boxOAuth2Api: { - includeCredentialsOnRefreshOnBody: true, - }, - shopifyOAuth2Api: { - tokenType: 'Bearer', - keyToIncludeInAccessTokenHeader: 'X-Shopify-Access-Token', - }, - }; - - const additionalOAuth2Options = oAuth2Options[nodeCredentialType]; + const additionalOAuth2Options = getOAuth2AdditionalParameters(nodeCredentialType); // service-specific cred: OAuth1, OAuth2, plain const requestWithAuthentication = this.helpers.requestWithAuthentication.call( diff --git a/packages/nodes-base/nodes/HttpRequest/V3/HttpRequestV3.node.ts b/packages/nodes-base/nodes/HttpRequest/V3/HttpRequestV3.node.ts index b728088ebca..e87183993af 100644 --- a/packages/nodes-base/nodes/HttpRequest/V3/HttpRequestV3.node.ts +++ b/packages/nodes-base/nodes/HttpRequest/V3/HttpRequestV3.node.ts @@ -6,14 +6,13 @@ import { INodeType, INodeTypeBaseDescription, INodeTypeDescription, - IOAuth2Options, NodeApiError, NodeOperationError, } from 'n8n-workflow'; import { OptionsWithUri } from 'request-promise-native'; -import { replaceNullValues } from '../GenericFunctions'; +import { getOAuth2AdditionalParameters, replaceNullValues } from '../GenericFunctions'; export class HttpRequestV3 implements INodeType { description: INodeTypeDescription; @@ -1145,25 +1144,7 @@ export class HttpRequestV3 implements INodeType { requestPromises.push(request); } } else if (authentication === 'predefinedCredentialType' && nodeCredentialType) { - const oAuth2Options: { [credentialType: string]: IOAuth2Options } = { - clickUpOAuth2Api: { - keepBearer: false, - tokenType: 'Bearer', - }, - slackOAuth2Api: { - tokenType: 'Bearer', - property: 'authed_user.access_token', - }, - boxOAuth2Api: { - includeCredentialsOnRefreshOnBody: true, - }, - shopifyOAuth2Api: { - tokenType: 'Bearer', - keyToIncludeInAccessTokenHeader: 'X-Shopify-Access-Token', - }, - }; - - const additionalOAuth2Options = oAuth2Options[nodeCredentialType]; + const additionalOAuth2Options = getOAuth2AdditionalParameters(nodeCredentialType); // service-specific cred: OAuth1, OAuth2, plain @@ -1232,7 +1213,7 @@ export class HttpRequestV3 implements INodeType { } else { responseFormat = 'text'; const data = Buffer.from(response.body).toString(); - response.body = (!data) ? undefined : data; + response.body = !data ? undefined : data; } } From 2e916b65644d4b844a4a626a0f0b92c2dd476128 Mon Sep 17 00:00:00 2001 From: Jonathan Bennetts Date: Tue, 11 Oct 2022 08:50:23 +0100 Subject: [PATCH 585/609] fix(GitLab Trigger Node): fix issue with trigger not always activating (#4303) --- packages/nodes-base/nodes/Gitlab/GitlabTrigger.node.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/nodes-base/nodes/Gitlab/GitlabTrigger.node.ts b/packages/nodes-base/nodes/Gitlab/GitlabTrigger.node.ts index d376239b9fa..f97bb43163e 100644 --- a/packages/nodes-base/nodes/Gitlab/GitlabTrigger.node.ts +++ b/packages/nodes-base/nodes/Gitlab/GitlabTrigger.node.ts @@ -6,7 +6,6 @@ import { INodeTypeDescription, IWebhookResponseData, NodeApiError, - NodeOperationError, } from 'n8n-workflow'; import { gitlabApiRequest } from './GenericFunctions'; @@ -196,7 +195,7 @@ export class GitlabTrigger implements INodeType { try { await gitlabApiRequest.call(this, 'GET', endpoint, {}); } catch (error) { - if (error.httpCode === '404') { + if (error.cause.httpCode === '404') { // Webhook does not exist delete webhookData.webhookId; delete webhookData.webhookEvents; From 69684fc4f761f970a740b68865304a17257ed20c Mon Sep 17 00:00:00 2001 From: Jonathan Bennetts Date: Tue, 11 Oct 2022 08:51:43 +0100 Subject: [PATCH 586/609] fix(seaTable Node): fix link items not showing in response (#4170) --- packages/nodes-base/nodes/SeaTable/GenericFunctions.ts | 4 ++++ packages/nodes-base/nodes/SeaTable/SeaTable.node.ts | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/packages/nodes-base/nodes/SeaTable/GenericFunctions.ts b/packages/nodes-base/nodes/SeaTable/GenericFunctions.ts index ebd14a4b6dc..71c5be28141 100644 --- a/packages/nodes-base/nodes/SeaTable/GenericFunctions.ts +++ b/packages/nodes-base/nodes/SeaTable/GenericFunctions.ts @@ -258,6 +258,10 @@ function rowFormatColumn(input: unknown): boolean | number | string | string[] | if (Array.isArray(input) && input.every((i) => typeof i === 'string')) { return input; + } else if (Array.isArray(input) && input.every((i) => typeof i === 'object')) { + const returnItems = [] as string[]; + input.every((i) => returnItems.push(i.display_value)); + return returnItems; } return null; diff --git a/packages/nodes-base/nodes/SeaTable/SeaTable.node.ts b/packages/nodes-base/nodes/SeaTable/SeaTable.node.ts index 86071be3975..9912a1fda81 100644 --- a/packages/nodes-base/nodes/SeaTable/SeaTable.node.ts +++ b/packages/nodes-base/nodes/SeaTable/SeaTable.node.ts @@ -294,6 +294,10 @@ export class SeaTable implements INodeType { Object.assign(qs, filters, options); + if (qs.convert_link_id === false) { + delete qs.convert_link_id; + } + if (returnAll) { responseData = await setableApiRequestAllItems.call( this, From 0c78df61eaf8e1ea95cb0e794135e79f7258e6a3 Mon Sep 17 00:00:00 2001 From: Csaba Tuncsik Date: Tue, 11 Oct 2022 10:06:33 +0200 Subject: [PATCH 587/609] refactor(editor): encapsulate node creation actions (#4287) * refactor(editor): encapsulate node creation actions * fix(editor): add sticky node event name * refactor(editor): move node creation and load it dynamically * refactor(editor): move node creator * refactor(editor): move node creator from node view to node creation * fix(editor): fix node creator opening --- .../src/components/Node/NodeCreation.vue | 131 +++++++++++++++++ .../{ => Node}/NodeCreator/CategoryItem.vue | 0 .../{ => Node}/NodeCreator/CreatorItem.vue | 0 .../{ => Node}/NodeCreator/ItemIterator.vue | 0 .../{ => Node}/NodeCreator/MainPanel.vue | 2 +- .../{ => Node}/NodeCreator/NoResults.vue | 0 .../{ => Node}/NodeCreator/NoResultsIcon.vue | 0 .../{ => Node}/NodeCreator/NodeCreator.vue | 46 +++--- .../{ => Node}/NodeCreator/NodeItem.vue | 8 +- .../{ => Node}/NodeCreator/SearchBar.vue | 0 .../NodeCreator/SubcategoryItem.vue | 0 .../NodeCreator/SubcategoryPanel.vue | 1 - .../{ => Node}/NodeCreator/helpers.ts | 0 .../src/components/mixins/nodeBase.ts | 2 +- packages/editor-ui/src/views/NodeView.vue | 138 ++---------------- 15 files changed, 176 insertions(+), 152 deletions(-) create mode 100644 packages/editor-ui/src/components/Node/NodeCreation.vue rename packages/editor-ui/src/components/{ => Node}/NodeCreator/CategoryItem.vue (100%) rename packages/editor-ui/src/components/{ => Node}/NodeCreator/CreatorItem.vue (100%) rename packages/editor-ui/src/components/{ => Node}/NodeCreator/ItemIterator.vue (100%) rename packages/editor-ui/src/components/{ => Node}/NodeCreator/MainPanel.vue (99%) rename packages/editor-ui/src/components/{ => Node}/NodeCreator/NoResults.vue (100%) rename packages/editor-ui/src/components/{ => Node}/NodeCreator/NoResultsIcon.vue (100%) rename packages/editor-ui/src/components/{ => Node}/NodeCreator/NodeCreator.vue (84%) rename packages/editor-ui/src/components/{ => Node}/NodeCreator/NodeItem.vue (96%) rename packages/editor-ui/src/components/{ => Node}/NodeCreator/SearchBar.vue (100%) rename packages/editor-ui/src/components/{ => Node}/NodeCreator/SubcategoryItem.vue (100%) rename packages/editor-ui/src/components/{ => Node}/NodeCreator/SubcategoryPanel.vue (97%) rename packages/editor-ui/src/components/{ => Node}/NodeCreator/helpers.ts (100%) diff --git a/packages/editor-ui/src/components/Node/NodeCreation.vue b/packages/editor-ui/src/components/Node/NodeCreation.vue new file mode 100644 index 00000000000..a567dd305ba --- /dev/null +++ b/packages/editor-ui/src/components/Node/NodeCreation.vue @@ -0,0 +1,131 @@ + + + + + diff --git a/packages/editor-ui/src/components/NodeCreator/CategoryItem.vue b/packages/editor-ui/src/components/Node/NodeCreator/CategoryItem.vue similarity index 100% rename from packages/editor-ui/src/components/NodeCreator/CategoryItem.vue rename to packages/editor-ui/src/components/Node/NodeCreator/CategoryItem.vue diff --git a/packages/editor-ui/src/components/NodeCreator/CreatorItem.vue b/packages/editor-ui/src/components/Node/NodeCreator/CreatorItem.vue similarity index 100% rename from packages/editor-ui/src/components/NodeCreator/CreatorItem.vue rename to packages/editor-ui/src/components/Node/NodeCreator/CreatorItem.vue diff --git a/packages/editor-ui/src/components/NodeCreator/ItemIterator.vue b/packages/editor-ui/src/components/Node/NodeCreator/ItemIterator.vue similarity index 100% rename from packages/editor-ui/src/components/NodeCreator/ItemIterator.vue rename to packages/editor-ui/src/components/Node/NodeCreator/ItemIterator.vue diff --git a/packages/editor-ui/src/components/NodeCreator/MainPanel.vue b/packages/editor-ui/src/components/Node/NodeCreator/MainPanel.vue similarity index 99% rename from packages/editor-ui/src/components/NodeCreator/MainPanel.vue rename to packages/editor-ui/src/components/Node/NodeCreator/MainPanel.vue index efc2a3d3c35..95a93086109 100644 --- a/packages/editor-ui/src/components/NodeCreator/MainPanel.vue +++ b/packages/editor-ui/src/components/Node/NodeCreator/MainPanel.vue @@ -67,7 +67,7 @@ import SearchBar from './SearchBar.vue'; import SubcategoryPanel from './SubcategoryPanel.vue'; import { INodeCreateElement, INodeItemProps, ISubcategoryItemProps } from '@/Interface'; import { ALL_NODE_FILTER, CORE_NODES_CATEGORY, REGULAR_NODE_FILTER, TRIGGER_NODE_FILTER } from '@/constants'; -import SlideTransition from '../transitions/SlideTransition.vue'; +import SlideTransition from '../../transitions/SlideTransition.vue'; import { matchesNodeType, matchesSelectType } from './helpers'; export default mixins(externalHooks).extend({ diff --git a/packages/editor-ui/src/components/NodeCreator/NoResults.vue b/packages/editor-ui/src/components/Node/NodeCreator/NoResults.vue similarity index 100% rename from packages/editor-ui/src/components/NodeCreator/NoResults.vue rename to packages/editor-ui/src/components/Node/NodeCreator/NoResults.vue diff --git a/packages/editor-ui/src/components/NodeCreator/NoResultsIcon.vue b/packages/editor-ui/src/components/Node/NodeCreator/NoResultsIcon.vue similarity index 100% rename from packages/editor-ui/src/components/NodeCreator/NoResultsIcon.vue rename to packages/editor-ui/src/components/Node/NodeCreator/NoResultsIcon.vue diff --git a/packages/editor-ui/src/components/NodeCreator/NodeCreator.vue b/packages/editor-ui/src/components/Node/NodeCreator/NodeCreator.vue similarity index 84% rename from packages/editor-ui/src/components/NodeCreator/NodeCreator.vue rename to packages/editor-ui/src/components/Node/NodeCreator/NodeCreator.vue index f15adc8cf79..8b2d04a15b3 100644 --- a/packages/editor-ui/src/components/NodeCreator/NodeCreator.vue +++ b/packages/editor-ui/src/components/Node/NodeCreator/NodeCreator.vue @@ -1,23 +1,21 @@ - - diff --git a/packages/editor-ui/src/components/ParameterInputHint.vue b/packages/editor-ui/src/components/ParameterInputHint.vue index 3bdd4336a33..9d0075cd9ee 100644 --- a/packages/editor-ui/src/components/ParameterInputHint.vue +++ b/packages/editor-ui/src/components/ParameterInputHint.vue @@ -1,9 +1,7 @@ + + + + diff --git a/packages/editor-ui/src/components/ParameterInputList.vue b/packages/editor-ui/src/components/ParameterInputList.vue index 6450068ba15..324ccd86697 100644 --- a/packages/editor-ui/src/components/ParameterInputList.vue +++ b/packages/editor-ui/src/components/ParameterInputList.vue @@ -45,6 +45,7 @@ :tooltipText="$locale.nodeText().inputLabelDescription(parameter, path)" size="small" :underline="true" + color="text-dark" /> +
+ + +
+ + + + + diff --git a/packages/editor-ui/src/components/ResourceLocator/ResourceLocator.vue b/packages/editor-ui/src/components/ResourceLocator/ResourceLocator.vue index fa44682c847..bd6511e627a 100644 --- a/packages/editor-ui/src/components/ResourceLocator/ResourceLocator.vue +++ b/packages/editor-ui/src/components/ResourceLocator/ResourceLocator.vue @@ -82,7 +82,7 @@ v-if="isValueExpression || droppable || forceShowExpression" type="text" :size="inputSize" - :value="activeDrop || forceShowExpression ? '' : expressionDisplayValue" + :value="expressionDisplayValue" :title="displayTitle" @keydown.stop ref="input" @@ -137,7 +137,6 @@
-
@@ -163,7 +162,6 @@ import { import DraggableTarget from '@/components/DraggableTarget.vue'; import ExpressionEdit from '@/components/ExpressionEdit.vue'; import ParameterIssues from '@/components/ParameterIssues.vue'; -import ParameterInputHint from '@/components/ParameterInputHint.vue'; import ResourceLocatorDropdown from './ResourceLocatorDropdown.vue'; import Vue, { PropType } from 'vue'; import { INodeUi, IResourceLocatorReqParams, IResourceLocatorResultExpanded } from '@/Interface'; @@ -172,7 +170,6 @@ import stringify from 'fast-json-stable-stringify'; import { workflowHelpers } from '../mixins/workflowHelpers'; import { nodeHelpers } from '../mixins/nodeHelpers'; import { getAppNameFromNodeName } from '../helpers'; -import { type } from 'os'; import { isResourceLocatorValue } from '@/typeGuards'; interface IResourceLocatorQuery { @@ -188,7 +185,6 @@ export default mixins(debounceHelper, workflowHelpers, nodeHelpers).extend({ DraggableTarget, ExpressionEdit, ParameterIssues, - ParameterInputHint, ResourceLocatorDropdown, }, props: { @@ -216,7 +212,7 @@ export default mixins(debounceHelper, workflowHelpers, nodeHelpers).extend({ type: String, default: '', }, - expressionDisplayValue: { + expressionComputedValue: { type: String, default: '', }, @@ -224,6 +220,9 @@ export default mixins(debounceHelper, workflowHelpers, nodeHelpers).extend({ type: Boolean, default: false, }, + expressionDisplayValue: { + type: String, + }, forceShowExpression: { type: Boolean, default: false, @@ -298,9 +297,6 @@ export default mixins(debounceHelper, workflowHelpers, nodeHelpers).extend({ return defaults[this.selectedMode] || ''; }, - infoText(): string { - return this.currentMode.hint ? this.currentMode.hint : ''; - }, currentMode(): INodePropertyMode { return this.findModeByName(this.selectedMode) || ({} as INodePropertyMode); }, @@ -327,8 +323,8 @@ export default mixins(debounceHelper, workflowHelpers, nodeHelpers).extend({ } if (this.selectedMode === 'url') { - if (this.isValueExpression && typeof this.expressionDisplayValue === 'string' && this.expressionDisplayValue.startsWith('http')) { - return this.expressionDisplayValue; + if (this.isValueExpression && typeof this.expressionComputedValue === 'string' && this.expressionComputedValue.startsWith('http')) { + return this.expressionComputedValue; } if (typeof this.valueToDisplay === 'string' && this.valueToDisplay.startsWith('http')) { @@ -337,7 +333,7 @@ export default mixins(debounceHelper, workflowHelpers, nodeHelpers).extend({ } if (this.currentMode.url) { - const value = this.isValueExpression? this.expressionDisplayValue : this.valueToDisplay; + const value = this.isValueExpression? this.expressionComputedValue : this.valueToDisplay; if (typeof value === 'string') { const expression = this.currentMode.url.replace(/\{\{\$value\}\}/g, value); const resolved = this.resolveExpression(expression); diff --git a/packages/editor-ui/src/components/RunData.vue b/packages/editor-ui/src/components/RunData.vue index 08544b574e8..6b92607ea71 100644 --- a/packages/editor-ui/src/components/RunData.vue +++ b/packages/editor-ui/src/components/RunData.vue @@ -220,8 +220,11 @@ :distanceFromActive="distanceFromActive" :showMappingHint="showMappingHint" :runIndex="runIndex" + :pageOffset="currentPageOffset" :totalRuns="maxRunIndex" + :hasDefaultHoverState="paneType === 'input'" @mounted="$emit('tableMounted', $event)" + @activeRowChanged="onItemHover" /> , }, mappingEnabled: { type: Boolean, @@ -463,6 +466,10 @@ export default mixins( this.showPinDataDiscoveryTooltip(this.jsonData); } } + this.$store.commit('ui/setNDVBranchIndex', { + pane: this.paneType, + branchIndex: this.currentOutputIndex, + }); }, destroyed() { this.hidePinDataDiscoveryTooltip(); @@ -561,6 +568,9 @@ export default mixins( return 0; }, + currentPageOffset(): number { + return this.pageSize * (this.currentPage - 1); + }, maxRunIndex (): number { if (this.node === null) { return 0; @@ -662,6 +672,17 @@ export default mixins( }, }, methods: { + onItemHover(itemIndex: number | null) { + if (itemIndex === null) { + this.$emit('itemHover', null); + + return; + } + this.$emit('itemHover', { + outputIndex: this.currentOutputIndex, + itemIndex, + }); + }, onClickDataPinningDocsLink() { this.$telemetry.track('User clicked ndv link', { workflow_id: this.$store.getters.workflowId, @@ -1094,6 +1115,12 @@ export default mixins( this.onDisplayModeChange('table'); } }, + currentOutputIndex(branchIndex: number) { + this.$store.commit('ui/setNDVBranchIndex', { + pane: this.paneType, + branchIndex, + }); + }, }, }); diff --git a/packages/editor-ui/src/components/RunDataTable.vue b/packages/editor-ui/src/components/RunDataTable.vue index e725e67787f..b03fc9bb714 100644 --- a/packages/editor-ui/src/components/RunDataTable.vue +++ b/packages/editor-ui/src/components/RunDataTable.vue @@ -5,8 +5,13 @@ - - + + {{ $locale.baseText('runData.emptyItemHint') }} @@ -88,10 +93,11 @@