From 50f568560fd9ca53a3787870d7512548658c17f1 Mon Sep 17 00:00:00 2001 From: Csaba Tuncsik Date: Wed, 22 Nov 2023 15:01:22 +0100 Subject: [PATCH 01/61] perf: Make frontend linting faster (no-changelog) (#7717) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: कारतोफ्फेलस्क्रिप्ट™ --- packages/@n8n_io/eslint-config/frontend.js | 4 + packages/@n8n_io/eslint-config/package.json | 30 +- packages/editor-ui/.eslintrc.js | 8 - packages/editor-ui/src/__tests__/utils.ts | 5 +- .../src/components/BreakpointsObserver.vue | 2 +- .../CredentialEdit/CredentialEdit.vue | 2 +- .../src/components/ExpressionEdit.vue | 13 +- .../ExpressionEditorModalOutput.vue | 2 +- .../InlineExpressionEditorOutput.vue | 2 +- .../Node/NodeCreator/ItemTypes/NodeItem.vue | 2 +- .../src/components/NodeCredentials.vue | 11 +- .../editor-ui/src/components/NodeSettings.vue | 2 +- .../src/components/ParameterInput.vue | 8 +- packages/editor-ui/src/mixins/debounce.ts | 22 +- .../editor-ui/src/mixins/genericHelpers.ts | 6 +- .../src/stores/externalSecrets.ee.store.ts | 13 +- .../editor-ui/src/stores/workflows.store.ts | 8 +- packages/editor-ui/src/utils/apiUtils.ts | 2 +- packages/editor-ui/src/utils/sortUtils.ts | 5 +- packages/editor-ui/src/views/NodeView.vue | 1 + .../editor-ui/src/views/SettingsLdapView.vue | 2 +- pnpm-lock.yaml | 752 ++++++++---------- 22 files changed, 420 insertions(+), 482 deletions(-) diff --git a/packages/@n8n_io/eslint-config/frontend.js b/packages/@n8n_io/eslint-config/frontend.js index a93c510e2052a..3f07fb4c9d27b 100644 --- a/packages/@n8n_io/eslint-config/frontend.js +++ b/packages/@n8n_io/eslint-config/frontend.js @@ -36,12 +36,16 @@ module.exports = { 'vue/v-slot-style': 'error', 'vue/no-unused-components': 'error', 'vue/multi-word-component-names': 'off', + '@typescript-eslint/no-explicit-any': 'error', // TODO: fix these '@typescript-eslint/no-unsafe-call': 'off', '@typescript-eslint/no-unsafe-assignment': 'off', + '@typescript-eslint/no-unsafe-argument': 'off', + '@typescript-eslint/no-unsafe-return': 'off', '@typescript-eslint/restrict-template-expressions': 'off', '@typescript-eslint/unbound-method': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', // TODO: remove these 'vue/no-mutating-props': 'warn', diff --git a/packages/@n8n_io/eslint-config/package.json b/packages/@n8n_io/eslint-config/package.json index 18cc51681a994..0343f58d7c009 100644 --- a/packages/@n8n_io/eslint-config/package.json +++ b/packages/@n8n_io/eslint-config/package.json @@ -3,21 +3,21 @@ "private": true, "version": "0.0.1", "devDependencies": { - "@types/eslint": "^8.44.1", - "@typescript-eslint/eslint-plugin": "^6.2.0", - "@typescript-eslint/parser": "^6.2.0", - "@vue/eslint-config-typescript": "^11.0.3", - "eslint": "^8.45.0", - "eslint-config-airbnb-typescript": "^17.1.0", - "eslint-config-prettier": "^8.9.0", - "eslint-import-resolver-typescript": "^3.5.5", - "eslint-plugin-import": "^2.28.0", - "eslint-plugin-n8n-local-rules": "^1.0.0", - "eslint-plugin-prettier": "^5.0.0", - "eslint-plugin-unicorn": "^48.0.1", - "eslint-plugin-unused-imports": "^3.0.0", - "eslint-plugin-vue": "^9.15.1", - "vue-eslint-parser": "^9.3.1" + "@types/eslint": "8.44.7", + "@typescript-eslint/eslint-plugin": "6.2.0", + "@typescript-eslint/parser": "6.2.0", + "@vue/eslint-config-typescript": "12.0.0", + "eslint": "8.54.0", + "eslint-config-airbnb-typescript": "17.1.0", + "eslint-config-prettier": "9.0.0", + "eslint-import-resolver-typescript": "3.5.5", + "eslint-plugin-import": "2.28.0", + "eslint-plugin-n8n-local-rules": "1.0.0", + "eslint-plugin-prettier": "5.0.1", + "eslint-plugin-unicorn": "49.0.0", + "eslint-plugin-unused-imports": "3.0.0", + "eslint-plugin-vue": "9.18.1", + "vue-eslint-parser": "9.3.2" }, "scripts": { "clean": "rimraf .turbo", diff --git a/packages/editor-ui/.eslintrc.js b/packages/editor-ui/.eslintrc.js index 45e532bdee669..135863cbf2c01 100644 --- a/packages/editor-ui/.eslintrc.js +++ b/packages/editor-ui/.eslintrc.js @@ -30,11 +30,6 @@ module.exports = { '@typescript-eslint/no-this-alias': 'warn', '@typescript-eslint/no-unnecessary-boolean-literal-compare': 'warn', '@typescript-eslint/no-unnecessary-type-assertion': 'warn', - '@typescript-eslint/no-unsafe-argument': 'warn', - '@typescript-eslint/no-unsafe-assignment': 'warn', - '@typescript-eslint/no-unsafe-call': 'warn', - '@typescript-eslint/no-unsafe-member-access': 'warn', - '@typescript-eslint/no-unsafe-return': 'warn', '@typescript-eslint/no-unused-expressions': 'warn', '@typescript-eslint/no-unused-vars': 'warn', '@typescript-eslint/no-use-before-define': 'warn', @@ -42,12 +37,9 @@ module.exports = { '@typescript-eslint/prefer-nullish-coalescing': 'warn', '@typescript-eslint/prefer-optional-chain': 'warn', '@typescript-eslint/restrict-plus-operands': 'warn', - '@typescript-eslint/restrict-template-expressions': 'warn', - '@typescript-eslint/unbound-method': 'warn', '@typescript-eslint/ban-ts-comment': ['warn', { 'ts-ignore': true }], '@typescript-eslint/no-redundant-type-constituents': 'warn', '@typescript-eslint/no-base-to-string': 'warn', - '@typescript-eslint/no-explicit-any': 'warn', '@typescript-eslint/no-unsafe-enum-comparison': 'warn', }, }; diff --git a/packages/editor-ui/src/__tests__/utils.ts b/packages/editor-ui/src/__tests__/utils.ts index 836b5608fbdbd..37f64f5c0bb9a 100644 --- a/packages/editor-ui/src/__tests__/utils.ts +++ b/packages/editor-ui/src/__tests__/utils.ts @@ -1,7 +1,10 @@ import type { ISettingsState } from '@/Interface'; import { UserManagementAuthenticationMethod } from '@/Interface'; -export const retry = async (assertion: () => any, { interval = 20, timeout = 1000 } = {}) => { +export const retry = async ( + assertion: () => ReturnType, + { interval = 20, timeout = 1000 } = {}, +) => { return new Promise((resolve, reject) => { const startTime = Date.now(); diff --git a/packages/editor-ui/src/components/BreakpointsObserver.vue b/packages/editor-ui/src/components/BreakpointsObserver.vue index 40372c0062cfd..669531616c026 100644 --- a/packages/editor-ui/src/components/BreakpointsObserver.vue +++ b/packages/editor-ui/src/components/BreakpointsObserver.vue @@ -70,7 +70,7 @@ export default defineComponent({ return 'SM'; }, - value(): any | undefined { + value(): number | undefined { if (this.valueXS !== undefined && this.width < BREAKPOINT_SM) { return this.valueXS; } diff --git a/packages/editor-ui/src/components/CredentialEdit/CredentialEdit.vue b/packages/editor-ui/src/components/CredentialEdit/CredentialEdit.vue index c4f3de45c4224..99d40c4b28b8c 100644 --- a/packages/editor-ui/src/components/CredentialEdit/CredentialEdit.vue +++ b/packages/editor-ui/src/components/CredentialEdit/CredentialEdit.vue @@ -686,7 +686,7 @@ export default defineComponent({ this.hasUnsavedChanges = true; }, - onDataChange({ name, value }: { name: string; value: any }) { + onDataChange({ name, value }: { name: string; value: CredentialInformation }) { // skip update if new value matches the current if (this.credentialData[name] === value) return; diff --git a/packages/editor-ui/src/components/ExpressionEdit.vue b/packages/editor-ui/src/components/ExpressionEdit.vue index 246a4d1af1f2d..1c42692a4976c 100644 --- a/packages/editor-ui/src/components/ExpressionEdit.vue +++ b/packages/editor-ui/src/components/ExpressionEdit.vue @@ -147,7 +147,11 @@ export default defineComponent({ }, itemSelected(eventData: IVariableItemSelected) { - (this.$refs.inputFieldExpression as any).itemSelected(eventData); + ( + this.$refs.inputFieldExpression as { + itemSelected: (variable: IVariableItemSelected) => void; + } + ).itemSelected(eventData); void this.$externalHooks().run('expressionEdit.itemSelected', { parameter: this.parameter, value: this.modelValue, @@ -224,8 +228,11 @@ export default defineComponent({ this.latestValue = this.modelValue; const resolvedExpressionValue = - (this.$refs.expressionResult && (this.$refs.expressionResult as any).getValue()) || - undefined; + ( + this.$refs.expressionResult as { + getValue: () => string; + } + )?.getValue() || ''; void this.$externalHooks().run('expressionEdit.dialogVisibleChanged', { dialogVisible: newValue, parameter: this.parameter, diff --git a/packages/editor-ui/src/components/ExpressionEditorModal/ExpressionEditorModalOutput.vue b/packages/editor-ui/src/components/ExpressionEditorModal/ExpressionEditorModalOutput.vue index 8891fe05fdfee..56f7ecf7cfc60 100644 --- a/packages/editor-ui/src/components/ExpressionEditorModal/ExpressionEditorModalOutput.vue +++ b/packages/editor-ui/src/components/ExpressionEditorModal/ExpressionEditorModalOutput.vue @@ -78,7 +78,7 @@ export default defineComponent({ segment.kind === 'plaintext' ? segment.plaintext.length : segment.resolved - ? (segment.resolved as any).toString().length + ? segment.resolved.toString().length : 0; segment.to = cursor; diff --git a/packages/editor-ui/src/components/InlineExpressionEditor/InlineExpressionEditorOutput.vue b/packages/editor-ui/src/components/InlineExpressionEditor/InlineExpressionEditorOutput.vue index e0020daf3d351..9c0d64c507e6c 100644 --- a/packages/editor-ui/src/components/InlineExpressionEditor/InlineExpressionEditorOutput.vue +++ b/packages/editor-ui/src/components/InlineExpressionEditor/InlineExpressionEditorOutput.vue @@ -119,7 +119,7 @@ export default defineComponent({ segment.kind === 'plaintext' ? segment.plaintext.length : segment.resolved - ? (segment.resolved as any).toString().length + ? segment.resolved.toString().length : 0; segment.to = cursor; return segment; diff --git a/packages/editor-ui/src/components/Node/NodeCreator/ItemTypes/NodeItem.vue b/packages/editor-ui/src/components/Node/NodeCreator/ItemTypes/NodeItem.vue index b974601128375..f933e524d780d 100644 --- a/packages/editor-ui/src/components/Node/NodeCreator/ItemTypes/NodeItem.vue +++ b/packages/editor-ui/src/components/Node/NodeCreator/ItemTypes/NodeItem.vue @@ -114,7 +114,7 @@ const draggableStyle = computed<{ top: string; left: string }>(() => ({ const isCommunityNode = computed(() => isCommunityPackageName(props.nodeType.name)); -const displayName = computed(() => { +const displayName = computed(() => { const displayName = props.nodeType.displayName.trimEnd(); return i18n.headerText({ diff --git a/packages/editor-ui/src/components/NodeCredentials.vue b/packages/editor-ui/src/components/NodeCredentials.vue index c6121cee3ce6a..4c7bbf9f98ee5 100644 --- a/packages/editor-ui/src/components/NodeCredentials.vue +++ b/packages/editor-ui/src/components/NodeCredentials.vue @@ -346,10 +346,13 @@ export default defineComponent({ let options: CredentialDropdownOption[] = []; types.forEach((type) => { options = options.concat( - this.credentialsStore.allUsableCredentialsByType[type].map((option: any) => ({ - ...option, - typeDisplayName: this.credentialsStore.getCredentialTypeByName(type)?.displayName, - })), + this.credentialsStore.allUsableCredentialsByType[type].map( + (option: ICredentialsResponse) => + ({ + ...option, + typeDisplayName: this.credentialsStore.getCredentialTypeByName(type)?.displayName, + }) as CredentialDropdownOption, + ), ); }); return options; diff --git a/packages/editor-ui/src/components/NodeSettings.vue b/packages/editor-ui/src/components/NodeSettings.vue index 7aca1f287d9f1..f96d6016ab55d 100644 --- a/packages/editor-ui/src/components/NodeSettings.vue +++ b/packages/editor-ui/src/components/NodeSettings.vue @@ -399,7 +399,7 @@ export default defineComponent({ try { parameters = JSON.parse(parameters) as { - [key: string]: any; + [key: string]: unknown; }; //@ts-ignore diff --git a/packages/editor-ui/src/components/ParameterInput.vue b/packages/editor-ui/src/components/ParameterInput.vue index ac8db135448aa..0fc67812d3fb3 100644 --- a/packages/editor-ui/src/components/ParameterInput.vue +++ b/packages/editor-ui/src/components/ParameterInput.vue @@ -421,6 +421,8 @@ import { useI18n } from '@/composables'; import type { N8nInput } from 'n8n-design-system'; import { isCredentialOnlyNodeType } from '@/utils/credentialOnlyNodes'; +type Picker = { $emit: (arg0: string, arg1: Date) => void }; + export default defineComponent({ name: 'parameter-input', mixins: [externalHooks, nodeHelpers, workflowHelpers, debounceHelper], @@ -525,14 +527,14 @@ export default defineComponent({ { text: 'Today', // TODO - onClick(picker: any) { + onClick(picker: Picker) { picker.$emit('pick', new Date()); }, }, { text: 'Yesterday', // TODO - onClick(picker: any) { + onClick(picker: Picker) { const date = new Date(); date.setTime(date.getTime() - 3600 * 1000 * 24); picker.$emit('pick', date); @@ -541,7 +543,7 @@ export default defineComponent({ { text: 'A week ago', // TODO - onClick(picker: any) { + onClick(picker: Picker) { const date = new Date(); date.setTime(date.getTime() - 3600 * 1000 * 24 * 7); picker.$emit('pick', date); diff --git a/packages/editor-ui/src/mixins/debounce.ts b/packages/editor-ui/src/mixins/debounce.ts index e4c9a34454c3b..bd4d2dc035109 100644 --- a/packages/editor-ui/src/mixins/debounce.ts +++ b/packages/editor-ui/src/mixins/debounce.ts @@ -4,25 +4,27 @@ import { defineComponent } from 'vue'; export const debounceHelper = defineComponent({ data() { return { - debouncedFunctions: [] as any[], + debouncedFunctions: {} as Record Promise | void>, }; }, methods: { - async callDebounced(...inputParameters: any[]): Promise { - const functionName = inputParameters.shift() as string; - const { trailing, debounceTime } = inputParameters.shift(); - - // @ts-ignore + async callDebounced( + functionName: string, + options: { debounceTime: number; trailing?: boolean }, + ...inputParameters: unknown[] + ): Promise { + const { trailing, debounceTime } = options; if (this.debouncedFunctions[functionName] === undefined) { - // @ts-ignore this.debouncedFunctions[functionName] = debounce( - this[functionName], + async (...args: unknown[]) => { + // @ts-ignore + await this[functionName](...args); + }, debounceTime, trailing ? { trailing } : { leading: true }, ); } - // @ts-ignore - await this.debouncedFunctions[functionName].apply(this, inputParameters); + await this.debouncedFunctions[functionName](...inputParameters); }, }, }); diff --git a/packages/editor-ui/src/mixins/genericHelpers.ts b/packages/editor-ui/src/mixins/genericHelpers.ts index 52d50e9a78cf8..b92ec7eace568 100644 --- a/packages/editor-ui/src/mixins/genericHelpers.ts +++ b/packages/editor-ui/src/mixins/genericHelpers.ts @@ -13,7 +13,7 @@ export const genericHelpers = defineComponent({ }, data() { return { - loadingService: null as any | null, + loadingService: null as null | { close: () => void; text: string }, }; }, computed: { @@ -75,7 +75,9 @@ export const genericHelpers = defineComponent({ }); }, setLoadingText(text: string) { - this.loadingService.text = text; + if (this.loadingService !== null) { + this.loadingService.text = text; + } }, stopLoading() { if (this.loadingService !== null) { diff --git a/packages/editor-ui/src/stores/externalSecrets.ee.store.ts b/packages/editor-ui/src/stores/externalSecrets.ee.store.ts index 66d7349d9e81e..e646cb0ed9c7d 100644 --- a/packages/editor-ui/src/stores/externalSecrets.ee.store.ts +++ b/packages/editor-ui/src/stores/externalSecrets.ee.store.ts @@ -37,17 +37,18 @@ export const useExternalSecretsStore = defineStore('externalSecrets', () => { secretAcc[secret] = '*********'; return secretAcc; } - const obj = (secretAcc[splitSecret[0]] ?? {}) as object; - let acc: any = obj; + const obj = secretAcc[splitSecret[0]] ?? {}; + let acc = obj; for (let i = 1; i < splitSecret.length; i++) { - const key = splitSecret[i]; + const key = splitSecret[i] as keyof typeof acc; // Actual value key if (i === splitSecret.length - 1) { - acc[key] = '*********'; + const key = splitSecret[i] as keyof typeof acc; + acc[key] = '*********' as (typeof acc)[typeof key]; continue; } - if (!(key in acc)) { - acc[key] = {}; + if (Object.keys(acc) && !acc[key]) { + acc[key] = {} as (typeof acc)[typeof key]; } acc = acc[key]; } diff --git a/packages/editor-ui/src/stores/workflows.store.ts b/packages/editor-ui/src/stores/workflows.store.ts index 829d38aec150d..b0b5315b60b99 100644 --- a/packages/editor-ui/src/stores/workflows.store.ts +++ b/packages/editor-ui/src/stores/workflows.store.ts @@ -750,16 +750,14 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, { } // Check if the same connection exists already - const checkProperties = ['index', 'node', 'type']; - let propertyName: string; + const checkProperties = ['index', 'node', 'type'] as Array; + let propertyName: keyof IConnection; let connectionExists = false; connectionLoop: for (const existingConnection of this.workflow.connections[sourceData.node][ sourceData.type ][sourceData.index]) { for (propertyName of checkProperties) { - if ( - (existingConnection as any)[propertyName] !== (destinationData as any)[propertyName] - ) { + if (existingConnection[propertyName] !== destinationData[propertyName]) { continue connectionLoop; } } diff --git a/packages/editor-ui/src/utils/apiUtils.ts b/packages/editor-ui/src/utils/apiUtils.ts index 6705d6b578ba1..25cd464017c0f 100644 --- a/packages/editor-ui/src/utils/apiUtils.ts +++ b/packages/editor-ui/src/utils/apiUtils.ts @@ -102,7 +102,7 @@ export async function makeRestApiRequest( context: IRestApiContext, method: Method, endpoint: string, - data?: any, + data?: IDataObject, ) { const response = await request({ method, diff --git a/packages/editor-ui/src/utils/sortUtils.ts b/packages/editor-ui/src/utils/sortUtils.ts index 5fc1b5a1b87da..7dbc780634ae6 100644 --- a/packages/editor-ui/src/utils/sortUtils.ts +++ b/packages/editor-ui/src/utils/sortUtils.ts @@ -203,10 +203,11 @@ function getValue(obj: T, prop: string): unknown { const segments = prop.split('.'); - let result: any = obj; + let result = obj; let i = 0; while (result && i < segments.length) { - result = result[segments[i]]; + const key = segments[i] as keyof T; + result = result[key] as T; i++; } return result; diff --git a/packages/editor-ui/src/views/NodeView.vue b/packages/editor-ui/src/views/NodeView.vue index bd0e8b3f5675f..785473a8c43f7 100644 --- a/packages/editor-ui/src/views/NodeView.vue +++ b/packages/editor-ui/src/views/NodeView.vue @@ -305,6 +305,7 @@ import type { INodeUpdatePropertiesInformation, NodeCreatorOpenSource, AddedNodesAndConnections, + ToggleNodeCreatorOptions, } from '@/Interface'; import { debounceHelper } from '@/mixins/debounce'; diff --git a/packages/editor-ui/src/views/SettingsLdapView.vue b/packages/editor-ui/src/views/SettingsLdapView.vue index 6f2ea006e7b7c..36029c073eb01 100644 --- a/packages/editor-ui/src/views/SettingsLdapView.vue +++ b/packages/editor-ui/src/views/SettingsLdapView.vue @@ -682,7 +682,7 @@ export default defineComponent({ this.showError(error, this.$locale.baseText('settings.ldap.configurationError')); } }, - async getLdapSynchronizations(state: any) { + async getLdapSynchronizations(state: { loaded: () => void; complete: () => void }) { try { this.loadingTable = true; const data = await this.settingsStore.getLdapSynchronizations({ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5a4b9b40e6dc7..8adf0a1c67a97 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -146,50 +146,50 @@ importers: packages/@n8n_io/eslint-config: devDependencies: '@types/eslint': - specifier: ^8.44.1 - version: 8.44.1 + specifier: 8.44.7 + version: 8.44.7 '@typescript-eslint/eslint-plugin': - specifier: ^6.2.0 - version: 6.2.0(@typescript-eslint/parser@6.2.0)(eslint@8.45.0)(typescript@5.3.2) + specifier: 6.2.0 + version: 6.2.0(@typescript-eslint/parser@6.2.0)(eslint@8.54.0)(typescript@5.3.2) '@typescript-eslint/parser': - specifier: ^6.2.0 - version: 6.2.0(eslint@8.45.0)(typescript@5.3.2) + specifier: 6.2.0 + version: 6.2.0(eslint@8.54.0)(typescript@5.3.2) '@vue/eslint-config-typescript': - specifier: ^11.0.3 - version: 11.0.3(eslint-plugin-vue@9.15.1)(eslint@8.45.0)(typescript@5.3.2) + specifier: 12.0.0 + version: 12.0.0(eslint-plugin-vue@9.18.1)(eslint@8.54.0)(typescript@5.3.2) eslint: - specifier: ^8.45.0 - version: 8.45.0 + specifier: 8.54.0 + version: 8.54.0 eslint-config-airbnb-typescript: - specifier: ^17.1.0 - version: 17.1.0(@typescript-eslint/eslint-plugin@6.2.0)(@typescript-eslint/parser@6.2.0)(eslint-plugin-import@2.28.0)(eslint@8.45.0) + specifier: 17.1.0 + version: 17.1.0(@typescript-eslint/eslint-plugin@6.2.0)(@typescript-eslint/parser@6.2.0)(eslint-plugin-import@2.28.0)(eslint@8.54.0) eslint-config-prettier: - specifier: ^8.9.0 - version: 8.9.0(eslint@8.45.0) + specifier: 9.0.0 + version: 9.0.0(eslint@8.54.0) eslint-import-resolver-typescript: - specifier: ^3.5.5 - version: 3.5.5(@typescript-eslint/parser@6.2.0)(eslint-plugin-import@2.28.0)(eslint@8.45.0) + specifier: 3.5.5 + version: 3.5.5(@typescript-eslint/parser@6.2.0)(eslint-plugin-import@2.28.0)(eslint@8.54.0) eslint-plugin-import: - specifier: ^2.28.0 - version: 2.28.0(@typescript-eslint/parser@6.2.0)(eslint-import-resolver-typescript@3.5.5)(eslint@8.45.0) + specifier: 2.28.0 + version: 2.28.0(@typescript-eslint/parser@6.2.0)(eslint-import-resolver-typescript@3.5.5)(eslint@8.54.0) eslint-plugin-n8n-local-rules: - specifier: ^1.0.0 + specifier: 1.0.0 version: 1.0.0 eslint-plugin-prettier: - specifier: ^5.0.0 - version: 5.0.0(@types/eslint@8.44.1)(eslint-config-prettier@8.9.0)(eslint@8.45.0)(prettier@3.0.3) + specifier: 5.0.1 + version: 5.0.1(@types/eslint@8.44.7)(eslint-config-prettier@9.0.0)(eslint@8.54.0)(prettier@3.0.3) eslint-plugin-unicorn: - specifier: ^48.0.1 - version: 48.0.1(eslint@8.45.0) + specifier: 49.0.0 + version: 49.0.0(eslint@8.54.0) eslint-plugin-unused-imports: - specifier: ^3.0.0 - version: 3.0.0(@typescript-eslint/eslint-plugin@6.2.0)(eslint@8.45.0) + specifier: 3.0.0 + version: 3.0.0(@typescript-eslint/eslint-plugin@6.2.0)(eslint@8.54.0) eslint-plugin-vue: - specifier: ^9.15.1 - version: 9.15.1(eslint@8.45.0) + specifier: 9.18.1 + version: 9.18.1(eslint@8.54.0) vue-eslint-parser: - specifier: ^9.3.1 - version: 9.3.1(eslint@8.45.0) + specifier: 9.3.2 + version: 9.3.2(eslint@8.54.0) packages/cli: dependencies: @@ -1302,7 +1302,7 @@ importers: version: 0.4.11 eslint-plugin-n8n-nodes-base: specifier: ^1.16.0 - version: 1.16.0(eslint@8.45.0)(typescript@5.3.2) + version: 1.16.0(eslint@8.54.0)(typescript@5.3.2) gulp: specifier: ^4.0.0 version: 4.0.2 @@ -2285,7 +2285,7 @@ packages: '@babel/helper-plugin-utils': 7.22.5 debug: 4.3.4(supports-color@8.1.1) lodash.debounce: 4.0.8 - resolve: 1.22.3 + resolve: 1.22.8 transitivePeerDependencies: - supports-color dev: true @@ -2335,7 +2335,7 @@ packages: '@babel/helper-module-imports': 7.22.5 '@babel/helper-simple-access': 7.22.5 '@babel/helper-split-export-declaration': 7.22.6 - '@babel/helper-validator-identifier': 7.22.5 + '@babel/helper-validator-identifier': 7.22.20 dev: true /@babel/helper-optimise-call-expression@7.22.5: @@ -2399,8 +2399,8 @@ packages: resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==} engines: {node: '>=6.9.0'} - /@babel/helper-validator-identifier@7.22.5: - resolution: {integrity: sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==} + /@babel/helper-validator-identifier@7.22.20: + resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} engines: {node: '>=6.9.0'} /@babel/helper-validator-option@7.22.5: @@ -2432,7 +2432,7 @@ packages: resolution: {integrity: sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-validator-identifier': 7.22.5 + '@babel/helper-validator-identifier': 7.22.20 chalk: 2.4.2 js-tokens: 4.0.0 dev: true @@ -3011,7 +3011,7 @@ packages: '@babel/helper-hoist-variables': 7.22.5 '@babel/helper-module-transforms': 7.22.9(@babel/core@7.22.9) '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-validator-identifier': 7.22.5 + '@babel/helper-validator-identifier': 7.22.20 dev: true /@babel/plugin-transform-modules-umd@7.22.5(@babel/core@7.22.9): @@ -3471,7 +3471,7 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/helper-string-parser': 7.22.5 - '@babel/helper-validator-identifier': 7.22.5 + '@babel/helper-validator-identifier': 7.22.20 to-fast-properties: 2.0.0 /@bcoe/v8-coverage@0.2.3: @@ -3840,19 +3840,14 @@ packages: dev: true optional: true - /@eslint-community/eslint-utils@4.4.0(eslint@8.45.0): + /@eslint-community/eslint-utils@4.4.0(eslint@8.54.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 dependencies: - eslint: 8.45.0 - eslint-visitor-keys: 3.4.1 - dev: true - - /@eslint-community/regexpp@4.5.0: - resolution: {integrity: sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + eslint: 8.54.0 + eslint-visitor-keys: 3.4.3 dev: true /@eslint-community/regexpp@4.6.2: @@ -3860,8 +3855,8 @@ packages: engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} dev: true - /@eslint/eslintrc@2.1.0: - resolution: {integrity: sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==} + /@eslint/eslintrc@2.1.3: + resolution: {integrity: sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 @@ -3877,8 +3872,8 @@ packages: - supports-color dev: true - /@eslint/js@8.44.0: - resolution: {integrity: sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==} + /@eslint/js@8.54.0: + resolution: {integrity: sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true @@ -4040,11 +4035,11 @@ packages: '@hapi/hoek': 9.3.0 dev: true - /@humanwhocodes/config-array@0.11.10: - resolution: {integrity: sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==} + /@humanwhocodes/config-array@0.11.13: + resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==} engines: {node: '>=10.10.0'} dependencies: - '@humanwhocodes/object-schema': 1.2.1 + '@humanwhocodes/object-schema': 2.0.1 debug: 4.3.4(supports-color@8.1.1) minimatch: 3.1.2 transitivePeerDependencies: @@ -4056,8 +4051,8 @@ packages: engines: {node: '>=12.22'} dev: true - /@humanwhocodes/object-schema@1.2.1: - resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + /@humanwhocodes/object-schema@2.0.1: + resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==} dev: true /@icetee/ftp@0.3.15: @@ -7637,12 +7632,12 @@ packages: /@types/eslint-scope@3.7.4: resolution: {integrity: sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==} dependencies: - '@types/eslint': 8.44.1 + '@types/eslint': 8.44.7 '@types/estree': 1.0.0 dev: true - /@types/eslint@8.44.1: - resolution: {integrity: sha512-XpNDc4Z5Tb4x+SW1MriMVeIsMoONHCkWFMkR/aPJbzEsxqHy+4Glu/BqTdPrApfDeMaXbtNh6bseNgl5KaWrSg==} + /@types/eslint@8.44.7: + resolution: {integrity: sha512-f5ORu2hcBbKei97U73mf+l9t4zTGl74IqZ0GQk4oVea/VS8tQZYkUveSYojk+frraAVYId0V2WC9O4PTNru2FQ==} dependencies: '@types/estree': 1.0.0 '@types/json-schema': 7.0.12 @@ -8230,36 +8225,38 @@ packages: dev: true optional: true - /@typescript-eslint/eslint-plugin@5.59.5(@typescript-eslint/parser@5.59.5)(eslint@8.45.0)(typescript@5.3.2): - resolution: {integrity: sha512-feA9xbVRWJZor+AnLNAr7A8JRWeZqHUf4T9tlP+TN04b05pFVhO5eN7/O93Y/1OUlLMHKbnJisgDURs/qvtqdg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/eslint-plugin@6.2.0(@typescript-eslint/parser@6.2.0)(eslint@8.54.0)(typescript@5.3.2): + resolution: {integrity: sha512-rClGrMuyS/3j0ETa1Ui7s6GkLhfZGKZL3ZrChLeAiACBE/tRc1wq8SNZESUuluxhLj9FkUefRs2l6bCIArWBiQ==} + engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: - '@typescript-eslint/parser': ^5.0.0 - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha + eslint: ^7.0.0 || ^8.0.0 typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: '@eslint-community/regexpp': 4.6.2 - '@typescript-eslint/parser': 5.59.5(eslint@8.45.0)(typescript@5.3.2) - '@typescript-eslint/scope-manager': 5.59.5 - '@typescript-eslint/type-utils': 5.59.5(eslint@8.45.0)(typescript@5.3.2) - '@typescript-eslint/utils': 5.59.5(eslint@8.45.0)(typescript@5.3.2) + '@typescript-eslint/parser': 6.2.0(eslint@8.54.0)(typescript@5.3.2) + '@typescript-eslint/scope-manager': 6.2.0 + '@typescript-eslint/type-utils': 6.2.0(eslint@8.54.0)(typescript@5.3.2) + '@typescript-eslint/utils': 6.2.0(eslint@8.54.0)(typescript@5.3.2) + '@typescript-eslint/visitor-keys': 6.2.0 debug: 4.3.4(supports-color@8.1.1) - eslint: 8.45.0 - grapheme-splitter: 1.0.4 + eslint: 8.54.0 + graphemer: 1.4.0 ignore: 5.2.4 + natural-compare: 1.4.0 natural-compare-lite: 1.4.0 semver: 7.5.4 - tsutils: 3.21.0(typescript@5.3.2) + ts-api-utils: 1.0.1(typescript@5.3.2) typescript: 5.3.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/eslint-plugin@6.2.0(@typescript-eslint/parser@6.2.0)(eslint@8.45.0)(typescript@5.3.2): - resolution: {integrity: sha512-rClGrMuyS/3j0ETa1Ui7s6GkLhfZGKZL3ZrChLeAiACBE/tRc1wq8SNZESUuluxhLj9FkUefRs2l6bCIArWBiQ==} + /@typescript-eslint/eslint-plugin@6.7.5(@typescript-eslint/parser@6.7.5)(eslint@8.54.0)(typescript@5.3.2): + resolution: {integrity: sha512-JhtAwTRhOUcP96D0Y6KYnwig/MRQbOoLGXTON2+LlyB/N35SP9j1boai2zzwXb7ypKELXMx3DVk9UTaEq1vHEw==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha @@ -8270,17 +8267,16 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.6.2 - '@typescript-eslint/parser': 6.2.0(eslint@8.45.0)(typescript@5.3.2) - '@typescript-eslint/scope-manager': 6.2.0 - '@typescript-eslint/type-utils': 6.2.0(eslint@8.45.0)(typescript@5.3.2) - '@typescript-eslint/utils': 6.2.0(eslint@8.45.0)(typescript@5.3.2) - '@typescript-eslint/visitor-keys': 6.2.0 + '@typescript-eslint/parser': 6.7.5(eslint@8.54.0)(typescript@5.3.2) + '@typescript-eslint/scope-manager': 6.7.5 + '@typescript-eslint/type-utils': 6.7.5(eslint@8.54.0)(typescript@5.3.2) + '@typescript-eslint/utils': 6.7.5(eslint@8.54.0)(typescript@5.3.2) + '@typescript-eslint/visitor-keys': 6.7.5 debug: 4.3.4(supports-color@8.1.1) - eslint: 8.45.0 + eslint: 8.54.0 graphemer: 1.4.0 ignore: 5.2.4 natural-compare: 1.4.0 - natural-compare-lite: 1.4.0 semver: 7.5.4 ts-api-utils: 1.0.1(typescript@5.3.2) typescript: 5.3.2 @@ -8288,28 +8284,29 @@ packages: - supports-color dev: true - /@typescript-eslint/parser@5.59.5(eslint@8.45.0)(typescript@5.3.2): - resolution: {integrity: sha512-NJXQC4MRnF9N9yWqQE2/KLRSOLvrrlZb48NGVfBa+RuPMN6B7ZcK5jZOvhuygv4D64fRKnZI4L4p8+M+rfeQuw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/parser@6.2.0(eslint@8.54.0)(typescript@5.3.2): + resolution: {integrity: sha512-igVYOqtiK/UsvKAmmloQAruAdUHihsOCvplJpplPZ+3h4aDkC/UKZZNKgB6h93ayuYLuEymU3h8nF1xMRbh37g==} + engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + eslint: ^7.0.0 || ^8.0.0 typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 5.59.5 - '@typescript-eslint/types': 5.59.5 - '@typescript-eslint/typescript-estree': 5.59.5(typescript@5.3.2) + '@typescript-eslint/scope-manager': 6.2.0 + '@typescript-eslint/types': 6.2.0 + '@typescript-eslint/typescript-estree': 6.2.0(typescript@5.3.2) + '@typescript-eslint/visitor-keys': 6.2.0 debug: 4.3.4(supports-color@8.1.1) - eslint: 8.45.0 + eslint: 8.54.0 typescript: 5.3.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/parser@6.2.0(eslint@8.45.0)(typescript@5.3.2): - resolution: {integrity: sha512-igVYOqtiK/UsvKAmmloQAruAdUHihsOCvplJpplPZ+3h4aDkC/UKZZNKgB6h93ayuYLuEymU3h8nF1xMRbh37g==} + /@typescript-eslint/parser@6.7.5(eslint@8.54.0)(typescript@5.3.2): + resolution: {integrity: sha512-bIZVSGx2UME/lmhLcjdVc7ePBwn7CLqKarUBL4me1C5feOd663liTGjMBGVcGr+BhnSLeP4SgwdvNnnkbIdkCw==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -8318,25 +8315,17 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 6.2.0 - '@typescript-eslint/types': 6.2.0 - '@typescript-eslint/typescript-estree': 6.2.0(typescript@5.3.2) - '@typescript-eslint/visitor-keys': 6.2.0 + '@typescript-eslint/scope-manager': 6.7.5 + '@typescript-eslint/types': 6.7.5 + '@typescript-eslint/typescript-estree': 6.7.5(typescript@5.3.2) + '@typescript-eslint/visitor-keys': 6.7.5 debug: 4.3.4(supports-color@8.1.1) - eslint: 8.45.0 + eslint: 8.54.0 typescript: 5.3.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/scope-manager@5.59.5: - resolution: {integrity: sha512-jVecWwnkX6ZgutF+DovbBJirZcAxgxC0EOHYt/niMROf8p4PwxxG32Qdhj/iIQQIuOflLjNkxoXyArkcIP7C3A==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - '@typescript-eslint/types': 5.59.5 - '@typescript-eslint/visitor-keys': 5.59.5 - dev: true - /@typescript-eslint/scope-manager@6.2.0: resolution: {integrity: sha512-1ZMNVgm5nnHURU8ZSJ3snsHzpFeNK84rdZjluEVBGNu7jDymfqceB3kdIZ6A4xCfEFFhRIB6rF8q/JIqJd2R0Q==} engines: {node: ^16.0.0 || >=18.0.0} @@ -8353,28 +8342,36 @@ packages: '@typescript-eslint/visitor-keys': 6.3.0 dev: true - /@typescript-eslint/type-utils@5.59.5(eslint@8.45.0)(typescript@5.3.2): - resolution: {integrity: sha512-4eyhS7oGym67/pSxA2mmNq7X164oqDYNnZCUayBwJZIRVvKpBCMBzFnFxjeoDeShjtO6RQBHBuwybuX3POnDqg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/scope-manager@6.7.5: + resolution: {integrity: sha512-GAlk3eQIwWOJeb9F7MKQ6Jbah/vx1zETSDw8likab/eFcqkjSD7BI75SDAeC5N2L0MmConMoPvTsmkrg71+B1A==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 6.7.5 + '@typescript-eslint/visitor-keys': 6.7.5 + dev: true + + /@typescript-eslint/type-utils@6.2.0(eslint@8.54.0)(typescript@5.3.2): + resolution: {integrity: sha512-DnGZuNU2JN3AYwddYIqrVkYW0uUQdv0AY+kz2M25euVNlujcN2u+rJgfJsBFlUEzBB6OQkUqSZPyuTLf2bP5mw==} + engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: - eslint: '*' + eslint: ^7.0.0 || ^8.0.0 typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 5.59.5(typescript@5.3.2) - '@typescript-eslint/utils': 5.59.5(eslint@8.45.0)(typescript@5.3.2) + '@typescript-eslint/typescript-estree': 6.2.0(typescript@5.3.2) + '@typescript-eslint/utils': 6.2.0(eslint@8.54.0)(typescript@5.3.2) debug: 4.3.4(supports-color@8.1.1) - eslint: 8.45.0 - tsutils: 3.21.0(typescript@5.3.2) + eslint: 8.54.0 + ts-api-utils: 1.0.1(typescript@5.3.2) typescript: 5.3.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/type-utils@6.2.0(eslint@8.45.0)(typescript@5.3.2): - resolution: {integrity: sha512-DnGZuNU2JN3AYwddYIqrVkYW0uUQdv0AY+kz2M25euVNlujcN2u+rJgfJsBFlUEzBB6OQkUqSZPyuTLf2bP5mw==} + /@typescript-eslint/type-utils@6.7.5(eslint@8.54.0)(typescript@5.3.2): + resolution: {integrity: sha512-Gs0qos5wqxnQrvpYv+pf3XfcRXW6jiAn9zE/K+DlmYf6FcpxeNYN0AIETaPR7rHO4K2UY+D0CIbDP9Ut0U4m1g==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -8383,21 +8380,16 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 6.2.0(typescript@5.3.2) - '@typescript-eslint/utils': 6.2.0(eslint@8.45.0)(typescript@5.3.2) + '@typescript-eslint/typescript-estree': 6.7.5(typescript@5.3.2) + '@typescript-eslint/utils': 6.7.5(eslint@8.54.0)(typescript@5.3.2) debug: 4.3.4(supports-color@8.1.1) - eslint: 8.45.0 + eslint: 8.54.0 ts-api-utils: 1.0.1(typescript@5.3.2) typescript: 5.3.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/types@5.59.5: - resolution: {integrity: sha512-xkfRPHbqSH4Ggx4eHRIO/eGL8XL4Ysb4woL8c87YuAo8Md7AUjyWKa9YMwTL519SyDPrfEgKdewjkxNCVeJW7w==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true - /@typescript-eslint/types@6.2.0: resolution: {integrity: sha512-1nRRaDlp/XYJQLvkQJG5F3uBTno5SHPT7XVcJ5n1/k2WfNI28nJsvLakxwZRNY5spuatEKO7d5nZWsQpkqXwBA==} engines: {node: ^16.0.0 || >=18.0.0} @@ -8408,25 +8400,9 @@ packages: engines: {node: ^16.0.0 || >=18.0.0} dev: true - /@typescript-eslint/typescript-estree@5.59.5(typescript@5.3.2): - resolution: {integrity: sha512-+XXdLN2CZLZcD/mO7mQtJMvCkzRfmODbeSKuMY/yXbGkzvA9rJyDY5qDYNoiz2kP/dmyAxXquL2BvLQLJFPQIg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/types': 5.59.5 - '@typescript-eslint/visitor-keys': 5.59.5 - debug: 4.3.4(supports-color@8.1.1) - globby: 11.1.0 - is-glob: 4.0.3 - semver: 7.5.4 - tsutils: 3.21.0(typescript@5.3.2) - typescript: 5.3.2 - transitivePeerDependencies: - - supports-color + /@typescript-eslint/types@6.7.5: + resolution: {integrity: sha512-WboQBlOXtdj1tDFPyIthpKrUb+kZf2VroLZhxKa/VlwLlLyqv/PwUNgL30BlTVZV1Wu4Asu2mMYPqarSO4L5ZQ==} + engines: {node: ^16.0.0 || >=18.0.0} dev: true /@typescript-eslint/typescript-estree@6.2.0(typescript@5.3.2): @@ -8471,70 +8447,82 @@ packages: - supports-color dev: true - /@typescript-eslint/utils@5.59.5(eslint@8.45.0)(typescript@5.3.2): - resolution: {integrity: sha512-sCEHOiw+RbyTii9c3/qN74hYDPNORb8yWCoPLmB7BIflhplJ65u2PBpdRla12e3SSTJ2erRkPjz7ngLHhUegxA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/typescript-estree@6.7.5(typescript@5.3.2): + resolution: {integrity: sha512-NhJiJ4KdtwBIxrKl0BqG1Ur+uw7FiOnOThcYx9DpOGJ/Abc9z2xNzLeirCG02Ig3vkvrc2qFLmYSSsaITbKjlg==} + engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.45.0) - '@types/json-schema': 7.0.12 - '@types/semver': 7.5.0 - '@typescript-eslint/scope-manager': 5.59.5 - '@typescript-eslint/types': 5.59.5 - '@typescript-eslint/typescript-estree': 5.59.5(typescript@5.3.2) - eslint: 8.45.0 - eslint-scope: 5.1.1 + '@typescript-eslint/types': 6.7.5 + '@typescript-eslint/visitor-keys': 6.7.5 + debug: 4.3.4(supports-color@8.1.1) + globby: 11.1.0 + is-glob: 4.0.3 semver: 7.5.4 + ts-api-utils: 1.0.1(typescript@5.3.2) + typescript: 5.3.2 transitivePeerDependencies: - supports-color - - typescript dev: true - /@typescript-eslint/utils@6.2.0(eslint@8.45.0)(typescript@5.3.2): + /@typescript-eslint/utils@6.2.0(eslint@8.54.0)(typescript@5.3.2): resolution: {integrity: sha512-RCFrC1lXiX1qEZN8LmLrxYRhOkElEsPKTVSNout8DMzf8PeWoQG7Rxz2SadpJa3VSh5oYKGwt7j7X/VRg+Y3OQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.45.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.54.0) '@types/json-schema': 7.0.12 '@types/semver': 7.5.0 '@typescript-eslint/scope-manager': 6.2.0 '@typescript-eslint/types': 6.2.0 '@typescript-eslint/typescript-estree': 6.2.0(typescript@5.3.2) - eslint: 8.45.0 + eslint: 8.54.0 semver: 7.5.4 transitivePeerDependencies: - supports-color - typescript dev: true - /@typescript-eslint/utils@6.3.0(eslint@8.45.0)(typescript@5.3.2): + /@typescript-eslint/utils@6.3.0(eslint@8.54.0)(typescript@5.3.2): resolution: {integrity: sha512-hLLg3BZE07XHnpzglNBG8P/IXq/ZVXraEbgY7FM0Cnc1ehM8RMdn9mat3LubJ3KBeYXXPxV1nugWbQPjGeJk6Q==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.45.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.54.0) '@types/json-schema': 7.0.12 '@types/semver': 7.5.0 '@typescript-eslint/scope-manager': 6.3.0 '@typescript-eslint/types': 6.3.0 '@typescript-eslint/typescript-estree': 6.3.0(typescript@5.3.2) - eslint: 8.45.0 + eslint: 8.54.0 semver: 7.5.4 transitivePeerDependencies: - supports-color - typescript dev: true - /@typescript-eslint/visitor-keys@5.59.5: - resolution: {integrity: sha512-qL+Oz+dbeBRTeyJTIy0eniD3uvqU7x+y1QceBismZ41hd4aBSRh8UAw4pZP0+XzLuPZmx4raNMq/I+59W2lXKA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/utils@6.7.5(eslint@8.54.0)(typescript@5.3.2): + resolution: {integrity: sha512-pfRRrH20thJbzPPlPc4j0UNGvH1PjPlhlCMq4Yx7EGjV7lvEeGX0U6MJYe8+SyFutWgSHsdbJ3BXzZccYggezA==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 dependencies: - '@typescript-eslint/types': 5.59.5 - eslint-visitor-keys: 3.4.1 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.54.0) + '@types/json-schema': 7.0.12 + '@types/semver': 7.5.0 + '@typescript-eslint/scope-manager': 6.7.5 + '@typescript-eslint/types': 6.7.5 + '@typescript-eslint/typescript-estree': 6.7.5(typescript@5.3.2) + eslint: 8.54.0 + semver: 7.5.4 + transitivePeerDependencies: + - supports-color + - typescript dev: true /@typescript-eslint/visitor-keys@6.2.0: @@ -8542,7 +8530,7 @@ packages: engines: {node: ^16.0.0 || >=18.0.0} dependencies: '@typescript-eslint/types': 6.2.0 - eslint-visitor-keys: 3.4.1 + eslint-visitor-keys: 3.4.3 dev: true /@typescript-eslint/visitor-keys@6.3.0: @@ -8550,7 +8538,19 @@ packages: engines: {node: ^16.0.0 || >=18.0.0} dependencies: '@typescript-eslint/types': 6.3.0 - eslint-visitor-keys: 3.4.1 + eslint-visitor-keys: 3.4.3 + dev: true + + /@typescript-eslint/visitor-keys@6.7.5: + resolution: {integrity: sha512-3MaWdDZtLlsexZzDSdQWsFQ9l9nL8B80Z4fImSpyllFC/KLqWQRdEcB+gGGO+N3Q2uL40EsG66wZLsohPxNXvg==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 6.7.5 + eslint-visitor-keys: 3.4.3 + dev: true + + /@ungap/structured-clone@1.2.0: + resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} dev: true /@vitejs/plugin-vue@4.2.3(vite@4.4.7)(vue@3.3.4): @@ -8682,8 +8682,8 @@ packages: /@vue/devtools-api@6.5.0: resolution: {integrity: sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==} - /@vue/eslint-config-typescript@11.0.3(eslint-plugin-vue@9.15.1)(eslint@8.45.0)(typescript@5.3.2): - resolution: {integrity: sha512-dkt6W0PX6H/4Xuxg/BlFj5xHvksjpSlVjtkQCpaYJBIEuKj2hOVU7r+TIe+ysCwRYFz/lGqvklntRkCAibsbPw==} + /@vue/eslint-config-typescript@12.0.0(eslint-plugin-vue@9.18.1)(eslint@8.54.0)(typescript@5.3.2): + resolution: {integrity: sha512-StxLFet2Qe97T8+7L8pGlhYBBr8Eg05LPuTDVopQV6il+SK6qqom59BA/rcFipUef2jD8P2X44Vd8tMFytfvlg==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 @@ -8693,12 +8693,12 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/eslint-plugin': 5.59.5(@typescript-eslint/parser@5.59.5)(eslint@8.45.0)(typescript@5.3.2) - '@typescript-eslint/parser': 5.59.5(eslint@8.45.0)(typescript@5.3.2) - eslint: 8.45.0 - eslint-plugin-vue: 9.15.1(eslint@8.45.0) + '@typescript-eslint/eslint-plugin': 6.7.5(@typescript-eslint/parser@6.7.5)(eslint@8.54.0)(typescript@5.3.2) + '@typescript-eslint/parser': 6.7.5(eslint@8.54.0)(typescript@5.3.2) + eslint: 8.54.0 + eslint-plugin-vue: 9.18.1(eslint@8.54.0) typescript: 5.3.2 - vue-eslint-parser: 9.3.1(eslint@8.45.0) + vue-eslint-parser: 9.3.2(eslint@8.54.0) transitivePeerDependencies: - supports-color dev: true @@ -9333,14 +9333,14 @@ packages: /array-flatten@1.1.1: resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} - /array-includes@3.1.6: - resolution: {integrity: sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==} + /array-includes@3.1.7: + resolution: {integrity: sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.21.1 - get-intrinsic: 1.1.3 + define-properties: 1.2.0 + es-abstract: 1.22.1 + get-intrinsic: 1.2.1 is-string: 1.0.7 dev: true @@ -9390,34 +9390,34 @@ packages: engines: {node: '>=0.10.0'} dev: true - /array.prototype.findlastindex@1.2.2: - resolution: {integrity: sha512-tb5thFFlUcp7NdNF6/MpDk/1r/4awWG1FIz3YqDf+/zJSTezBb+/5WViH41obXULHVpDzoiCLpJ/ZO9YbJMsdw==} + /array.prototype.findlastindex@1.2.3: + resolution: {integrity: sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.21.1 + define-properties: 1.2.0 + es-abstract: 1.22.1 es-shim-unscopables: 1.0.0 - get-intrinsic: 1.1.3 + get-intrinsic: 1.2.1 dev: true - /array.prototype.flat@1.3.1: - resolution: {integrity: sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==} + /array.prototype.flat@1.3.2: + resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.21.1 + define-properties: 1.2.0 + es-abstract: 1.22.1 es-shim-unscopables: 1.0.0 dev: true - /array.prototype.flatmap@1.3.1: - resolution: {integrity: sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==} + /array.prototype.flatmap@1.3.2: + resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.21.1 + define-properties: 1.2.0 + es-abstract: 1.22.1 es-shim-unscopables: 1.0.0 dev: true @@ -10242,7 +10242,7 @@ packages: /call-bind@1.0.2: resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} dependencies: - function-bind: 1.1.1 + function-bind: 1.1.2 get-intrinsic: 1.2.1 /call-me-maybe@1.0.1: @@ -11439,14 +11439,6 @@ packages: resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} engines: {node: '>=8'} - /define-properties@1.1.4: - resolution: {integrity: sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==} - engines: {node: '>= 0.4'} - dependencies: - has-property-descriptors: 1.0.0 - object-keys: 1.1.1 - dev: true - /define-properties@1.2.0: resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==} engines: {node: '>= 0.4'} @@ -11903,45 +11895,6 @@ packages: is-arrayish: 0.2.1 dev: true - /es-abstract@1.21.1: - resolution: {integrity: sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==} - engines: {node: '>= 0.4'} - dependencies: - available-typed-arrays: 1.0.5 - call-bind: 1.0.2 - es-set-tostringtag: 2.0.1 - es-to-primitive: 1.2.1 - function-bind: 1.1.1 - function.prototype.name: 1.1.5 - get-intrinsic: 1.2.1 - get-symbol-description: 1.0.0 - globalthis: 1.0.3 - gopd: 1.0.1 - has: 1.0.3 - has-property-descriptors: 1.0.0 - has-proto: 1.0.1 - has-symbols: 1.0.3 - internal-slot: 1.0.5 - is-array-buffer: 3.0.2 - is-callable: 1.2.7 - is-negative-zero: 2.0.2 - is-regex: 1.1.4 - is-shared-array-buffer: 1.0.2 - is-string: 1.0.7 - is-typed-array: 1.1.10 - is-weakref: 1.0.2 - object-inspect: 1.12.3 - object-keys: 1.1.1 - object.assign: 4.1.4 - regexp.prototype.flags: 1.5.0 - safe-regex-test: 1.0.0 - string.prototype.trimend: 1.0.6 - string.prototype.trimstart: 1.0.6 - typed-array-length: 1.0.4 - unbox-primitive: 1.0.2 - which-typed-array: 1.1.11 - dev: true - /es-abstract@1.22.1: resolution: {integrity: sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==} engines: {node: '>= 0.4'} @@ -11992,7 +11945,7 @@ packages: dependencies: define-properties: 1.2.0 es-abstract: 1.22.1 - function-bind: 1.1.1 + function-bind: 1.1.2 functions-have-names: 1.2.3 get-intrinsic: 1.2.1 globalthis: 1.0.3 @@ -12168,7 +12121,7 @@ packages: source-map: 0.6.1 dev: true - /eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.28.0)(eslint@8.45.0): + /eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.28.0)(eslint@8.54.0): resolution: {integrity: sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==} engines: {node: ^10.12.0 || >=12.0.0} peerDependencies: @@ -12176,14 +12129,14 @@ packages: eslint-plugin-import: ^2.25.2 dependencies: confusing-browser-globals: 1.0.11 - eslint: 8.45.0 - eslint-plugin-import: 2.28.0(@typescript-eslint/parser@6.2.0)(eslint-import-resolver-typescript@3.5.5)(eslint@8.45.0) + eslint: 8.54.0 + eslint-plugin-import: 2.28.0(@typescript-eslint/parser@6.2.0)(eslint-import-resolver-typescript@3.5.5)(eslint@8.54.0) object.assign: 4.1.4 object.entries: 1.1.5 semver: 7.5.4 dev: true - /eslint-config-airbnb-typescript@17.1.0(@typescript-eslint/eslint-plugin@6.2.0)(@typescript-eslint/parser@6.2.0)(eslint-plugin-import@2.28.0)(eslint@8.45.0): + /eslint-config-airbnb-typescript@17.1.0(@typescript-eslint/eslint-plugin@6.2.0)(@typescript-eslint/parser@6.2.0)(eslint-plugin-import@2.28.0)(eslint@8.54.0): resolution: {integrity: sha512-GPxI5URre6dDpJ0CtcthSZVBAfI+Uw7un5OYNVxP2EYi3H81Jw701yFP7AU+/vCE7xBtFmjge7kfhhk4+RAiig==} peerDependencies: '@typescript-eslint/eslint-plugin': ^5.13.0 || ^6.0.0 @@ -12191,37 +12144,37 @@ packages: eslint: ^7.32.0 || ^8.2.0 eslint-plugin-import: ^2.25.3 dependencies: - '@typescript-eslint/eslint-plugin': 6.2.0(@typescript-eslint/parser@6.2.0)(eslint@8.45.0)(typescript@5.3.2) - '@typescript-eslint/parser': 6.2.0(eslint@8.45.0)(typescript@5.3.2) - eslint: 8.45.0 - eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.28.0)(eslint@8.45.0) - eslint-plugin-import: 2.28.0(@typescript-eslint/parser@6.2.0)(eslint-import-resolver-typescript@3.5.5)(eslint@8.45.0) + '@typescript-eslint/eslint-plugin': 6.2.0(@typescript-eslint/parser@6.2.0)(eslint@8.54.0)(typescript@5.3.2) + '@typescript-eslint/parser': 6.2.0(eslint@8.54.0)(typescript@5.3.2) + eslint: 8.54.0 + eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.28.0)(eslint@8.54.0) + eslint-plugin-import: 2.28.0(@typescript-eslint/parser@6.2.0)(eslint-import-resolver-typescript@3.5.5)(eslint@8.54.0) dev: true - /eslint-config-prettier@8.9.0(eslint@8.45.0): - resolution: {integrity: sha512-+sbni7NfVXnOpnRadUA8S28AUlsZt9GjgFvABIRL9Hkn8KqNzOp+7Lw4QWtrwn20KzU3wqu1QoOj2m+7rKRqkA==} + /eslint-config-prettier@9.0.0(eslint@8.54.0): + resolution: {integrity: sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==} hasBin: true peerDependencies: eslint: '>=7.0.0' dependencies: - eslint: 8.45.0 + eslint: 8.54.0 dev: true /eslint-config-riot@1.0.0: resolution: {integrity: sha512-NB/L/1Y30qyJcG5xZxCJKW/+bqyj+llbcCwo9DEz8bESIP0SLTOQ8T1DWCCFc+wJ61AMEstj4511PSScqMMfCw==} dev: false - /eslint-import-resolver-node@0.3.7: - resolution: {integrity: sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==} + /eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} dependencies: debug: 3.2.7(supports-color@5.5.0) - is-core-module: 2.12.1 - resolve: 1.22.3 + is-core-module: 2.13.1 + resolve: 1.22.8 transitivePeerDependencies: - supports-color dev: true - /eslint-import-resolver-typescript@3.5.5(@typescript-eslint/parser@6.2.0)(eslint-plugin-import@2.28.0)(eslint@8.45.0): + /eslint-import-resolver-typescript@3.5.5(@typescript-eslint/parser@6.2.0)(eslint-plugin-import@2.28.0)(eslint@8.54.0): resolution: {integrity: sha512-TdJqPHs2lW5J9Zpe17DZNQuDnox4xo2o+0tE7Pggain9Rbc19ik8kFtXdxZ250FVx2kF4vlt2RSf4qlUpG7bhw==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: @@ -12230,12 +12183,12 @@ packages: dependencies: debug: 4.3.4(supports-color@8.1.1) enhanced-resolve: 5.13.0 - eslint: 8.45.0 - eslint-module-utils: 2.7.4(@typescript-eslint/parser@6.2.0)(eslint-import-resolver-typescript@3.5.5)(eslint@8.45.0) - eslint-plugin-import: 2.28.0(@typescript-eslint/parser@6.2.0)(eslint-import-resolver-typescript@3.5.5)(eslint@8.45.0) + eslint: 8.54.0 + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.2.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.5.5)(eslint@8.54.0) + eslint-plugin-import: 2.28.0(@typescript-eslint/parser@6.2.0)(eslint-import-resolver-typescript@3.5.5)(eslint@8.54.0) get-tsconfig: 4.5.0 - globby: 13.1.3 - is-core-module: 2.11.0 + globby: 13.2.2 + is-core-module: 2.13.1 is-glob: 4.0.3 synckit: 0.8.5 transitivePeerDependencies: @@ -12245,36 +12198,7 @@ packages: - supports-color dev: true - /eslint-module-utils@2.7.4(@typescript-eslint/parser@6.2.0)(eslint-import-resolver-typescript@3.5.5)(eslint@8.45.0): - resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: '*' - eslint-import-resolver-node: '*' - eslint-import-resolver-typescript: '*' - eslint-import-resolver-webpack: '*' - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint: - optional: true - eslint-import-resolver-node: - optional: true - eslint-import-resolver-typescript: - optional: true - eslint-import-resolver-webpack: - optional: true - dependencies: - '@typescript-eslint/parser': 6.2.0(eslint@8.45.0)(typescript@5.3.2) - debug: 3.2.7(supports-color@5.5.0) - eslint: 8.45.0 - eslint-import-resolver-typescript: 3.5.5(@typescript-eslint/parser@6.2.0)(eslint-plugin-import@2.28.0)(eslint@8.45.0) - transitivePeerDependencies: - - supports-color - dev: true - - /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.2.0)(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5)(eslint@8.45.0): + /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.2.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.5.5)(eslint@8.54.0): resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} engines: {node: '>=4'} peerDependencies: @@ -12295,16 +12219,16 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 6.2.0(eslint@8.45.0)(typescript@5.3.2) + '@typescript-eslint/parser': 6.2.0(eslint@8.54.0)(typescript@5.3.2) debug: 3.2.7(supports-color@5.5.0) - eslint: 8.45.0 - eslint-import-resolver-node: 0.3.7 - eslint-import-resolver-typescript: 3.5.5(@typescript-eslint/parser@6.2.0)(eslint-plugin-import@2.28.0)(eslint@8.45.0) + eslint: 8.54.0 + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.5.5(@typescript-eslint/parser@6.2.0)(eslint-plugin-import@2.28.0)(eslint@8.54.0) transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-import@2.28.0(@typescript-eslint/parser@6.2.0)(eslint-import-resolver-typescript@3.5.5)(eslint@8.45.0): + /eslint-plugin-import@2.28.0(@typescript-eslint/parser@6.2.0)(eslint-import-resolver-typescript@3.5.5)(eslint@8.54.0): resolution: {integrity: sha512-B8s/n+ZluN7sxj9eUf7/pRFERX0r5bnFA2dCaLHy2ZeaQEAz0k+ZZkFWRFHJAqxfxQDx6KLv9LeIki7cFdwW+Q==} engines: {node: '>=4'} peerDependencies: @@ -12314,24 +12238,24 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 6.2.0(eslint@8.45.0)(typescript@5.3.2) - array-includes: 3.1.6 - array.prototype.findlastindex: 1.2.2 - array.prototype.flat: 1.3.1 - array.prototype.flatmap: 1.3.1 + '@typescript-eslint/parser': 6.2.0(eslint@8.54.0)(typescript@5.3.2) + array-includes: 3.1.7 + array.prototype.findlastindex: 1.2.3 + array.prototype.flat: 1.3.2 + array.prototype.flatmap: 1.3.2 debug: 3.2.7(supports-color@5.5.0) doctrine: 2.1.0 - eslint: 8.45.0 - eslint-import-resolver-node: 0.3.7 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.2.0)(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5)(eslint@8.45.0) + eslint: 8.54.0 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.2.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.5.5)(eslint@8.54.0) has: 1.0.3 - is-core-module: 2.12.1 + is-core-module: 2.13.1 is-glob: 4.0.3 minimatch: 3.1.2 - object.fromentries: 2.0.6 - object.groupby: 1.0.0 - object.values: 1.1.6 - resolve: 1.22.3 + object.fromentries: 2.0.7 + object.groupby: 1.0.1 + object.values: 1.1.7 + resolve: 1.22.8 semver: 7.5.4 tsconfig-paths: 4.2.0 transitivePeerDependencies: @@ -12344,11 +12268,11 @@ packages: resolution: {integrity: sha512-qe6sVFDP1Vj5eXlqZxYZpIjwYvhuqXlI0P8OfPyhiPOhMkFtr0TpFphD8/6WCzkm7LJCvG1eJEzURCtMIsFTAg==} dev: true - /eslint-plugin-n8n-nodes-base@1.16.0(eslint@8.45.0)(typescript@5.3.2): + /eslint-plugin-n8n-nodes-base@1.16.0(eslint@8.54.0)(typescript@5.3.2): resolution: {integrity: sha512-OEztJRuT/jv/WvwRXbXNirdYYddpAo2KZEJeOsVniK1ZCChuG4rrZJU3sgMRZMK6W9Pr613uWabW2q8tU2eKJg==} engines: {node: '>=18.10', pnpm: '>=8.6'} dependencies: - '@typescript-eslint/utils': 6.3.0(eslint@8.45.0)(typescript@5.3.2) + '@typescript-eslint/utils': 6.3.0(eslint@8.54.0)(typescript@5.3.2) camel-case: 4.1.2 indefinite: 2.4.3 pascal-case: 3.1.2 @@ -12361,8 +12285,8 @@ packages: - typescript dev: true - /eslint-plugin-prettier@5.0.0(@types/eslint@8.44.1)(eslint-config-prettier@8.9.0)(eslint@8.45.0)(prettier@3.0.3): - resolution: {integrity: sha512-AgaZCVuYDXHUGxj/ZGu1u8H8CYgDY3iG6w5kUFw4AzMVXzB7VvbKgYR4nATIN+OvUrghMbiDLeimVjVY5ilq3w==} + /eslint-plugin-prettier@5.0.1(@types/eslint@8.44.7)(eslint-config-prettier@9.0.0)(eslint@8.54.0)(prettier@3.0.3): + resolution: {integrity: sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: '@types/eslint': '>=8.0.0' @@ -12375,30 +12299,29 @@ packages: eslint-config-prettier: optional: true dependencies: - '@types/eslint': 8.44.1 - eslint: 8.45.0 - eslint-config-prettier: 8.9.0(eslint@8.45.0) + '@types/eslint': 8.44.7 + eslint: 8.54.0 + eslint-config-prettier: 9.0.0(eslint@8.54.0) prettier: 3.0.3 prettier-linter-helpers: 1.0.0 synckit: 0.8.5 dev: true - /eslint-plugin-unicorn@48.0.1(eslint@8.45.0): - resolution: {integrity: sha512-FW+4r20myG/DqFcCSzoumaddKBicIPeFnTrifon2mWIzlfyvzwyqZjqVP7m4Cqr/ZYisS2aiLghkUWaPg6vtCw==} + /eslint-plugin-unicorn@49.0.0(eslint@8.54.0): + resolution: {integrity: sha512-0fHEa/8Pih5cmzFW5L7xMEfUTvI9WKeQtjmKpTUmY+BiFCDxkxrTdnURJOHKykhtwIeyYsxnecbGvDCml++z4Q==} engines: {node: '>=16'} peerDependencies: - eslint: '>=8.44.0' + eslint: '>=8.52.0' dependencies: - '@babel/helper-validator-identifier': 7.22.5 - '@eslint-community/eslint-utils': 4.4.0(eslint@8.45.0) + '@babel/helper-validator-identifier': 7.22.20 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.54.0) ci-info: 3.8.0 clean-regexp: 1.0.0 - eslint: 8.45.0 + eslint: 8.54.0 esquery: 1.5.0 indent-string: 4.0.0 is-builtin-module: 3.2.1 jsesc: 3.0.2 - lodash: 4.17.21 pluralize: 8.0.0 read-pkg-up: 7.0.1 regexp-tree: 0.1.27 @@ -12407,7 +12330,7 @@ packages: strip-indent: 3.0.0 dev: true - /eslint-plugin-unused-imports@3.0.0(@typescript-eslint/eslint-plugin@6.2.0)(eslint@8.45.0): + /eslint-plugin-unused-imports@3.0.0(@typescript-eslint/eslint-plugin@6.2.0)(eslint@8.54.0): resolution: {integrity: sha512-sduiswLJfZHeeBJ+MQaG+xYzSWdRXoSw61DpU13mzWumCkR0ufD0HmO4kdNokjrkluMHpj/7PJeN35pgbhW3kw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -12417,24 +12340,24 @@ packages: '@typescript-eslint/eslint-plugin': optional: true dependencies: - '@typescript-eslint/eslint-plugin': 6.2.0(@typescript-eslint/parser@6.2.0)(eslint@8.45.0)(typescript@5.3.2) - eslint: 8.45.0 + '@typescript-eslint/eslint-plugin': 6.2.0(@typescript-eslint/parser@6.2.0)(eslint@8.54.0)(typescript@5.3.2) + eslint: 8.54.0 eslint-rule-composer: 0.3.0 dev: true - /eslint-plugin-vue@9.15.1(eslint@8.45.0): - resolution: {integrity: sha512-CJE/oZOslvmAR9hf8SClTdQ9JLweghT6JCBQNrT2Iel1uVw0W0OLJxzvPd6CxmABKCvLrtyDnqGV37O7KQv6+A==} + /eslint-plugin-vue@9.18.1(eslint@8.54.0): + resolution: {integrity: sha512-7hZFlrEgg9NIzuVik2I9xSnJA5RsmOfueYgsUGUokEDLJ1LHtxO0Pl4duje1BriZ/jDWb+44tcIlC3yi0tdlZg==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.45.0) - eslint: 8.45.0 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.54.0) + eslint: 8.54.0 natural-compare: 1.4.0 nth-check: 2.1.1 - postcss-selector-parser: 6.0.11 + postcss-selector-parser: 6.0.13 semver: 7.5.4 - vue-eslint-parser: 9.3.1(eslint@8.45.0) + vue-eslint-parser: 9.3.2(eslint@8.54.0) xml-name-validator: 4.0.0 transitivePeerDependencies: - supports-color @@ -12453,44 +12376,40 @@ packages: estraverse: 4.3.0 dev: true - /eslint-scope@7.2.0: - resolution: {integrity: sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==} + /eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: esrecurse: 4.3.0 estraverse: 5.3.0 dev: true - /eslint-visitor-keys@3.4.0: - resolution: {integrity: sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==} + /eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /eslint-visitor-keys@3.4.1: - resolution: {integrity: sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true - - /eslint@8.45.0: - resolution: {integrity: sha512-pd8KSxiQpdYRfYa9Wufvdoct3ZPQQuVuU5O6scNgMuOMYuxvH0IGaYK0wUFjo4UYYQQCUndlXiMbnxopwvvTiw==} + /eslint@8.54.0: + resolution: {integrity: sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.45.0) - '@eslint-community/regexpp': 4.5.0 - '@eslint/eslintrc': 2.1.0 - '@eslint/js': 8.44.0 - '@humanwhocodes/config-array': 0.11.10 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.54.0) + '@eslint-community/regexpp': 4.6.2 + '@eslint/eslintrc': 2.1.3 + '@eslint/js': 8.54.0 + '@humanwhocodes/config-array': 0.11.13 '@humanwhocodes/module-importer': 1.0.1 '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.2.0 ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 debug: 4.3.4(supports-color@8.1.1) doctrine: 3.0.0 escape-string-regexp: 4.0.0 - eslint-scope: 7.2.0 - eslint-visitor-keys: 3.4.1 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 espree: 9.6.1 esquery: 1.5.0 esutils: 2.0.3 @@ -12517,22 +12436,13 @@ packages: - supports-color dev: true - /espree@9.5.1: - resolution: {integrity: sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - acorn: 8.10.0 - acorn-jsx: 5.3.2(acorn@8.10.0) - eslint-visitor-keys: 3.4.1 - dev: true - /espree@9.6.1: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: acorn: 8.10.0 acorn-jsx: 5.3.2(acorn@8.10.0) - eslint-visitor-keys: 3.4.1 + eslint-visitor-keys: 3.4.3 dev: true /esprima-next@5.8.4: @@ -12927,6 +12837,17 @@ packages: merge2: 1.4.1 micromatch: 4.0.5 + /fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 + dev: true + /fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} @@ -13411,8 +13332,8 @@ packages: os: [darwin] optional: true - /function-bind@1.1.1: - resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} + /function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} /function.prototype.name@1.1.5: resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==} @@ -13506,18 +13427,10 @@ packages: resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==} dev: true - /get-intrinsic@1.1.3: - resolution: {integrity: sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==} - dependencies: - function-bind: 1.1.1 - has: 1.0.3 - has-symbols: 1.0.3 - dev: true - /get-intrinsic@1.2.1: resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==} dependencies: - function-bind: 1.1.1 + function-bind: 1.1.2 has: 1.0.3 has-proto: 1.0.1 has-symbols: 1.0.3 @@ -13775,12 +13688,12 @@ packages: merge2: 1.4.1 slash: 3.0.0 - /globby@13.1.3: - resolution: {integrity: sha512-8krCNHXvlCgHDpegPzleMq07yMYTO2sXKASmZmquEYWEmCx6J5UTRbp5RwMJkTJGtcQ44YpiUYUiN0b9mzy8Bw==} + /globby@13.2.2: + resolution: {integrity: sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dependencies: dir-glob: 3.0.1 - fast-glob: 3.2.12 + fast-glob: 3.3.2 ignore: 5.2.4 merge2: 1.4.1 slash: 4.0.0 @@ -13847,10 +13760,6 @@ packages: /graceful-fs@4.2.10: resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} - /grapheme-splitter@1.0.4: - resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} - dev: true - /graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} dev: true @@ -14006,12 +13915,18 @@ packages: resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} engines: {node: '>= 0.4.0'} dependencies: - function-bind: 1.1.1 + function-bind: 1.1.2 /hash-sum@1.0.2: resolution: {integrity: sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==} dev: true + /hasown@2.0.0: + resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==} + engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + /he@1.2.0: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true @@ -14553,16 +14468,16 @@ packages: ci-info: 3.8.0 dev: true - /is-core-module@2.11.0: - resolution: {integrity: sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==} + /is-core-module@2.12.1: + resolution: {integrity: sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==} dependencies: has: 1.0.3 dev: true - /is-core-module@2.12.1: - resolution: {integrity: sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==} + /is-core-module@2.13.1: + resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} dependencies: - has: 1.0.3 + hasown: 2.0.0 /is-data-descriptor@0.1.4: resolution: {integrity: sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==} @@ -15322,7 +15237,7 @@ packages: jest-pnp-resolver: 1.2.2(jest-resolve@29.6.2) jest-util: 29.6.2 jest-validate: 29.6.2 - resolve: 1.22.3 + resolve: 1.22.8 resolve.exports: 2.0.0 slash: 3.0.0 dev: true @@ -16035,7 +15950,7 @@ packages: is-plain-object: 2.0.4 object.map: 1.0.1 rechoir: 0.6.2 - resolve: 1.22.3 + resolve: 1.22.8 transitivePeerDependencies: - supports-color dev: true @@ -16593,7 +16508,7 @@ packages: dependencies: findup-sync: 2.0.0 micromatch: 3.1.10 - resolve: 1.22.3 + resolve: 1.22.8 stack-trace: 0.0.10 transitivePeerDependencies: - supports-color @@ -17346,7 +17261,7 @@ packages: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} dependencies: hosted-git-info: 2.8.9 - resolve: 1.22.3 + resolve: 1.22.8 semver: 7.5.4 validate-npm-package-license: 3.0.4 dev: true @@ -17534,13 +17449,13 @@ packages: es-abstract: 1.22.1 dev: true - /object.fromentries@2.0.6: - resolution: {integrity: sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==} + /object.fromentries@2.0.7: + resolution: {integrity: sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.21.1 + define-properties: 1.2.0 + es-abstract: 1.22.1 dev: true /object.getownpropertydescriptors@2.1.4: @@ -17553,8 +17468,8 @@ packages: es-abstract: 1.22.1 dev: false - /object.groupby@1.0.0: - resolution: {integrity: sha512-70MWG6NfRH9GnbZOikuhPPYzpUpof9iW2J9E4dW7FXTqPNb6rllE6u39SKwwiNh8lCwX3DDb5OgcKGiEBrTTyw==} + /object.groupby@1.0.1: + resolution: {integrity: sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==} dependencies: call-bind: 1.0.2 define-properties: 1.2.0 @@ -17585,13 +17500,13 @@ packages: make-iterator: 1.0.1 dev: true - /object.values@1.1.6: - resolution: {integrity: sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==} + /object.values@1.1.7: + resolution: {integrity: sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.21.1 + define-properties: 1.2.0 + es-abstract: 1.22.1 dev: true /on-finished@2.4.1: @@ -18354,6 +18269,14 @@ packages: util-deprecate: 1.0.2 dev: true + /postcss-selector-parser@6.0.13: + resolution: {integrity: sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==} + engines: {node: '>=4'} + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + dev: true + /postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} dev: true @@ -18644,7 +18567,7 @@ packages: jstransformer: 1.0.0 pug-error: 2.0.0 pug-walk: 2.0.0 - resolve: 1.22.3 + resolve: 1.22.8 dev: true /pug-lexer@5.0.1: @@ -19394,10 +19317,19 @@ packages: resolution: {integrity: sha512-P8ur/gp/AmbEzjr729bZnLjXK5Z+4P0zhIJgBgzqRih7hL7BOukHGtSTA3ACMY467GRFz3duQsi0bDZdR7DKdw==} hasBin: true dependencies: - is-core-module: 2.12.1 + is-core-module: 2.13.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + /resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + dependencies: + is-core-module: 2.13.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true + /restore-cursor@3.1.0: resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} engines: {node: '>=8'} @@ -21188,16 +21120,6 @@ packages: engines: {node: '>=0.6.x'} dev: false - /tsutils@3.21.0(typescript@5.3.2): - resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} - engines: {node: '>= 6'} - peerDependencies: - typescript: ^5.3.0 - dependencies: - tslib: 2.6.1 - typescript: 5.3.2 - dev: true - /tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} dependencies: @@ -22205,17 +22127,17 @@ packages: - vue dev: true - /vue-eslint-parser@9.3.1(eslint@8.45.0): - resolution: {integrity: sha512-Clr85iD2XFZ3lJ52/ppmUDG/spxQu6+MAeHXjjyI4I1NUYZ9xmenQp4N0oaHJhrA8OOxltCVxMRfANGa70vU0g==} + /vue-eslint-parser@9.3.2(eslint@8.54.0): + resolution: {integrity: sha512-q7tWyCVaV9f8iQyIA5Mkj/S6AoJ9KBN8IeUSf3XEmBrOtxOZnfTg5s4KClbZBCK3GtnT/+RyCLZyDHuZwTuBjg==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: '>=6.0.0' dependencies: debug: 4.3.4(supports-color@8.1.1) - eslint: 8.45.0 - eslint-scope: 7.2.0 - eslint-visitor-keys: 3.4.0 - espree: 9.5.1 + eslint: 8.54.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 esquery: 1.5.0 lodash: 4.17.21 semver: 7.5.4 From 96fd2c51bd702419c84cb4708484358902715bc4 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, 22 Nov 2023 17:45:26 +0100 Subject: [PATCH 02/61] fix(core): Show webhook urls for all webhook nodes (no-changelog) (#7783) This reverts parts of https://github.com/n8n-io/n8n/pull/7113 --- packages/core/bin/generate-ui-types | 16 ---------------- .../editor-ui/src/components/NodeWebhooks.vue | 2 +- packages/workflow/src/Interfaces.ts | 1 - 3 files changed, 1 insertion(+), 18 deletions(-) diff --git a/packages/core/bin/generate-ui-types b/packages/core/bin/generate-ui-types index 681cd809dda6a..988462d604e08 100755 --- a/packages/core/bin/generate-ui-types +++ b/packages/core/bin/generate-ui-types @@ -26,21 +26,6 @@ function findReferencedMethods(obj, refs = {}, latestName = '') { return refs; } -function addWebhookLifecycle(nodeType) { - if (nodeType.description.webhooks) { - nodeType.description.webhooks = nodeType.description.webhooks.map((webhook) => { - const webhookMethods = - nodeType?.webhookMethods?.[webhook.name] ?? nodeType?.webhookMethods?.default; - webhook.hasLifecycleMethods = Boolean( - webhookMethods?.checkExists && webhookMethods?.create && webhookMethods?.delete, - ); - return webhook; - }); - } - - return nodeType; -} - (async () => { const loader = new PackageDirectoryLoader(packageDir); await loader.loadAll(); @@ -79,7 +64,6 @@ function addWebhookLifecycle(nodeType) { .map((data) => { const nodeType = NodeHelpers.getVersionedNodeType(data.type); NodeHelpers.applySpecialNodeParameters(nodeType); - addWebhookLifecycle(nodeType); return data.type; }) .flatMap((nodeType) => diff --git a/packages/editor-ui/src/components/NodeWebhooks.vue b/packages/editor-ui/src/components/NodeWebhooks.vue index 0fec295a7f64f..2e7e31bfe6a6e 100644 --- a/packages/editor-ui/src/components/NodeWebhooks.vue +++ b/packages/editor-ui/src/components/NodeWebhooks.vue @@ -94,7 +94,7 @@ export default defineComponent({ } return (this.nodeType as INodeTypeDescription).webhooks!.filter( - (webhookData) => webhookData.restartWebhook !== true && !webhookData.hasLifecycleMethods, + (webhookData) => webhookData.restartWebhook !== true, ); }, baseText() { diff --git a/packages/workflow/src/Interfaces.ts b/packages/workflow/src/Interfaces.ts index 6e7ce8d5e283d..4b35633ec80a7 100644 --- a/packages/workflow/src/Interfaces.ts +++ b/packages/workflow/src/Interfaces.ts @@ -1650,7 +1650,6 @@ export interface IWebhookDescription { responseMode?: WebhookResponseMode | string; responseData?: WebhookResponseData | string; restartWebhook?: boolean; - hasLifecycleMethods?: boolean; // set automatically by generate-ui-types ndvHideUrl?: boolean; // If true the webhook will not be displayed in the editor ndvHideMethod?: boolean; // If true the method will not be displayed in the editor } From 99a9ea497a3d21739f911da5c88c076f60471bed Mon Sep 17 00:00:00 2001 From: Michael Kret <88898367+michael-radency@users.noreply.github.com> Date: Wed, 22 Nov 2023 18:49:56 +0200 Subject: [PATCH 03/61] feat(core): Add Support for custom CORS origins for webhooks (#7455) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit node-850 https://community.n8n.io/t/add-ability-to-set-cors-allow-list-in-n8n-webhooks/7610 https://community.n8n.io/t/configure-cors-pre-flight-request-option-method-in-the-roadmap/32189 --------- Co-authored-by: कारतोफ्फेलस्क्रिप्ट™ --- packages/cli/src/ActiveWorkflowRunner.ts | 56 ++++--- packages/cli/src/Interfaces.ts | 12 ++ packages/cli/src/TestWebhooks.ts | 26 +++- packages/cli/src/WebhookHelpers.ts | 23 ++- packages/cli/test/unit/WebhookHelpers.test.ts | 140 ++++++++++++++++++ packages/cli/test/unit/webhooks.test.ts | 10 +- .../nodes-base/nodes/Webhook/Webhook.node.ts | 1 + packages/workflow/src/Interfaces.ts | 3 +- packages/workflow/src/NodeHelpers.ts | 22 ++- 9 files changed, 264 insertions(+), 29 deletions(-) create mode 100644 packages/cli/test/unit/WebhookHelpers.test.ts diff --git a/packages/cli/src/ActiveWorkflowRunner.ts b/packages/cli/src/ActiveWorkflowRunner.ts index a32ce7aa3d85e..de684c9d2c626 100644 --- a/packages/cli/src/ActiveWorkflowRunner.ts +++ b/packages/cli/src/ActiveWorkflowRunner.ts @@ -23,6 +23,7 @@ import type { WorkflowExecuteMode, INodeType, IWebhookData, + IHttpRequestMethods, } from 'n8n-workflow'; import { NodeHelpers, @@ -39,6 +40,7 @@ import type { IWebhookManager, IWorkflowDb, IWorkflowExecutionDataProcess, + WebhookAccessControlOptions, WebhookRequest, } from '@/Interfaces'; import * as ResponseHelper from '@/ResponseHelper'; @@ -137,26 +139,14 @@ export class ActiveWorkflowRunner implements IWebhookManager { response: express.Response, ): Promise { const httpMethod = request.method; - let path = request.params.path; + const path = request.params.path; this.logger.debug(`Received webhook "${httpMethod}" for path "${path}"`); // Reset request parameters request.params = {} as WebhookRequest['params']; - // Remove trailing slash - if (path.endsWith('/')) { - path = path.slice(0, -1); - } - - const webhook = await this.webhookService.findWebhook(httpMethod, path); - - if (webhook === null) { - throw new ResponseHelper.NotFoundError( - webhookNotFoundErrorMessage(path, httpMethod), - WEBHOOK_PROD_UNREGISTERED_HINT, - ); - } + const webhook = await this.findWebhook(path, httpMethod); if (webhook.isDynamic) { const pathElements = path.split('/').slice(1); @@ -235,13 +225,45 @@ export class ActiveWorkflowRunner implements IWebhookManager { }); } - /** - * Gets all request methods associated with a single webhook - */ async getWebhookMethods(path: string) { return this.webhookService.getWebhookMethods(path); } + async findAccessControlOptions(path: string, httpMethod: IHttpRequestMethods) { + const webhook = await this.findWebhook(path, httpMethod); + + const workflowData = await this.workflowRepository.findOne({ + where: { id: webhook.workflowId }, + select: ['nodes'], + }); + + const nodes = workflowData?.nodes; + const webhookNode = nodes?.find( + ({ type, parameters, typeVersion }) => + parameters?.path === path && + (parameters?.httpMethod ?? 'GET') === httpMethod && + 'webhook' in this.nodeTypes.getByNameAndVersion(type, typeVersion), + ); + return webhookNode?.parameters?.options as WebhookAccessControlOptions; + } + + private async findWebhook(path: string, httpMethod: IHttpRequestMethods) { + // Remove trailing slash + if (path.endsWith('/')) { + path = path.slice(0, -1); + } + + const webhook = await this.webhookService.findWebhook(httpMethod, path); + if (webhook === null) { + throw new ResponseHelper.NotFoundError( + webhookNotFoundErrorMessage(path, httpMethod), + WEBHOOK_PROD_UNREGISTERED_HINT, + ); + } + + return webhook; + } + /** * Returns the ids of the currently active workflows from memory. */ diff --git a/packages/cli/src/Interfaces.ts b/packages/cli/src/Interfaces.ts index b47b1a91c7fc6..1caadbee578e9 100644 --- a/packages/cli/src/Interfaces.ts +++ b/packages/cli/src/Interfaces.ts @@ -267,8 +267,20 @@ export type WaitingWebhookRequest = WebhookRequest & { params: WebhookRequest['path'] & { suffix?: string }; }; +export interface WebhookAccessControlOptions { + allowedOrigins?: string; +} + export interface IWebhookManager { + /** Gets all request methods associated with a webhook path*/ getWebhookMethods?: (path: string) => Promise; + + /** Find the CORS options matching a path and method */ + findAccessControlOptions?: ( + path: string, + httpMethod: IHttpRequestMethods, + ) => Promise; + executeWebhook(req: WebhookRequest, res: Response): Promise; } diff --git a/packages/cli/src/TestWebhooks.ts b/packages/cli/src/TestWebhooks.ts index 4cd5d99809e18..a31e37ea6ba92 100644 --- a/packages/cli/src/TestWebhooks.ts +++ b/packages/cli/src/TestWebhooks.ts @@ -15,9 +15,11 @@ import type { IResponseCallbackData, IWebhookManager, IWorkflowDb, + WebhookAccessControlOptions, WebhookRequest, } from '@/Interfaces'; import { Push } from '@/push'; +import { NodeTypes } from '@/NodeTypes'; import * as ResponseHelper from '@/ResponseHelper'; import * as WebhookHelpers from '@/WebhookHelpers'; import { webhookNotFoundErrorMessage } from './utils'; @@ -38,8 +40,9 @@ export class TestWebhooks implements IWebhookManager { } = {}; constructor( - private activeWebhooks: ActiveWebhooks, - private push: Push, + private readonly activeWebhooks: ActiveWebhooks, + private readonly push: Push, + private readonly nodeTypes: NodeTypes, ) { activeWebhooks.testWebhooks = true; } @@ -161,9 +164,6 @@ export class TestWebhooks implements IWebhookManager { }); } - /** - * Gets all request methods associated with a single test webhook - */ async getWebhookMethods(path: string): Promise { const webhookMethods = this.activeWebhooks.getWebhookMethods(path); if (!webhookMethods.length) { @@ -177,6 +177,22 @@ export class TestWebhooks implements IWebhookManager { return webhookMethods; } + async findAccessControlOptions(path: string, httpMethod: IHttpRequestMethods) { + const webhookKey = Object.keys(this.testWebhookData).find( + (key) => key.includes(path) && key.startsWith(httpMethod), + ); + if (!webhookKey) return; + + const { workflow } = this.testWebhookData[webhookKey]; + const webhookNode = Object.values(workflow.nodes).find( + ({ type, parameters, typeVersion }) => + parameters?.path === path && + (parameters?.httpMethod ?? 'GET') === httpMethod && + 'webhook' in this.nodeTypes.getByNameAndVersion(type, typeVersion), + ); + return webhookNode?.parameters?.options as WebhookAccessControlOptions; + } + /** * Checks if it has to wait for webhook data to execute the workflow. * If yes it waits for it and resolves with the result of the workflow if not it simply resolves with undefined diff --git a/packages/cli/src/WebhookHelpers.ts b/packages/cli/src/WebhookHelpers.ts index 6a200e694f37a..ae87e130e9597 100644 --- a/packages/cli/src/WebhookHelpers.ts +++ b/packages/cli/src/WebhookHelpers.ts @@ -98,7 +98,28 @@ export const webhookRequestHandler = return ResponseHelper.sendErrorResponse(res, error as Error); } } - res.header('Access-Control-Allow-Origin', req.headers.origin); + + const requestedMethod = + method === 'OPTIONS' + ? (req.headers['access-control-request-method'] as IHttpRequestMethods) + : method; + if (webhookManager.findAccessControlOptions && requestedMethod) { + const options = await webhookManager.findAccessControlOptions(path, requestedMethod); + const { allowedOrigins } = options ?? {}; + + res.header( + 'Access-Control-Allow-Origin', + !allowedOrigins || allowedOrigins === '*' ? req.headers.origin : allowedOrigins, + ); + + if (method === 'OPTIONS') { + res.header('Access-Control-Max-Age', '300'); + const requestedHeaders = req.headers['access-control-request-headers']; + if (requestedHeaders?.length) { + res.header('Access-Control-Allow-Headers', requestedHeaders); + } + } + } } if (method === 'OPTIONS') { diff --git a/packages/cli/test/unit/WebhookHelpers.test.ts b/packages/cli/test/unit/WebhookHelpers.test.ts new file mode 100644 index 0000000000000..fb455b098a726 --- /dev/null +++ b/packages/cli/test/unit/WebhookHelpers.test.ts @@ -0,0 +1,140 @@ +import { type Response } from 'express'; +import { mock } from 'jest-mock-extended'; +import type { IHttpRequestMethods } from 'n8n-workflow'; +import type { IWebhookManager, WebhookCORSRequest, WebhookRequest } from '@/Interfaces'; +import { webhookRequestHandler } from '@/WebhookHelpers'; + +describe('WebhookHelpers', () => { + describe('webhookRequestHandler', () => { + const webhookManager = mock>(); + const handler = webhookRequestHandler(webhookManager); + + beforeEach(() => { + jest.resetAllMocks(); + }); + + it('should throw for unsupported methods', async () => { + const req = mock({ + method: 'CONNECT' as IHttpRequestMethods, + }); + const res = mock(); + res.status.mockReturnValue(res); + + await handler(req, res); + + expect(res.status).toHaveBeenCalledWith(500); + expect(res.json).toHaveBeenCalledWith({ + code: 0, + message: 'The method CONNECT is not supported.', + }); + }); + + describe('preflight requests', () => { + it('should handle missing header for requested method', async () => { + const req = mock({ + method: 'OPTIONS', + headers: { + origin: 'https://example.com/', + 'access-control-request-method': undefined, + }, + params: { path: 'test' }, + }); + const res = mock(); + res.status.mockReturnValue(res); + + webhookManager.getWebhookMethods.mockResolvedValue(['GET', 'PATCH']); + + await handler(req, res); + + expect(res.status).toHaveBeenCalledWith(204); + expect(res.header).toHaveBeenCalledWith( + 'Access-Control-Allow-Methods', + 'OPTIONS, GET, PATCH', + ); + }); + + it('should handle default origin and max-age', async () => { + const req = mock({ + method: 'OPTIONS', + headers: { + origin: 'https://example.com/', + 'access-control-request-method': 'GET', + }, + params: { path: 'test' }, + }); + const res = mock(); + res.status.mockReturnValue(res); + + webhookManager.getWebhookMethods.mockResolvedValue(['GET', 'PATCH']); + + await handler(req, res); + + expect(res.status).toHaveBeenCalledWith(204); + expect(res.header).toHaveBeenCalledWith( + 'Access-Control-Allow-Methods', + 'OPTIONS, GET, PATCH', + ); + expect(res.header).toHaveBeenCalledWith( + 'Access-Control-Allow-Origin', + 'https://example.com/', + ); + expect(res.header).toHaveBeenCalledWith('Access-Control-Max-Age', '300'); + }); + + it('should handle wildcard origin', async () => { + const randomOrigin = (Math.random() * 10e6).toString(16); + const req = mock({ + method: 'OPTIONS', + headers: { + origin: randomOrigin, + 'access-control-request-method': 'GET', + }, + params: { path: 'test' }, + }); + const res = mock(); + res.status.mockReturnValue(res); + + webhookManager.getWebhookMethods.mockResolvedValue(['GET', 'PATCH']); + webhookManager.findAccessControlOptions.mockResolvedValue({ + allowedOrigins: '*', + }); + + await handler(req, res); + + expect(res.status).toHaveBeenCalledWith(204); + expect(res.header).toHaveBeenCalledWith( + 'Access-Control-Allow-Methods', + 'OPTIONS, GET, PATCH', + ); + expect(res.header).toHaveBeenCalledWith('Access-Control-Allow-Origin', randomOrigin); + }); + + it('should handle custom origin', async () => { + const req = mock({ + method: 'OPTIONS', + headers: { + origin: 'https://example.com/', + 'access-control-request-method': 'GET', + }, + params: { path: 'test' }, + }); + const res = mock(); + res.status.mockReturnValue(res); + + webhookManager.getWebhookMethods.mockResolvedValue(['GET', 'PATCH']); + webhookManager.findAccessControlOptions.mockResolvedValue({ + allowedOrigins: 'https://test.com/', + }); + + await handler(req, res); + + expect(res.status).toHaveBeenCalledWith(204); + expect(res.header).toHaveBeenCalledWith( + 'Access-Control-Allow-Methods', + 'OPTIONS, GET, PATCH', + ); + expect(res.header).toHaveBeenCalledWith('Access-Control-Allow-Origin', 'https://test.com/'); + }); + }); + }); +}); diff --git a/packages/cli/test/unit/webhooks.test.ts b/packages/cli/test/unit/webhooks.test.ts index f6478806b4fc2..8d315f02d5213 100644 --- a/packages/cli/test/unit/webhooks.test.ts +++ b/packages/cli/test/unit/webhooks.test.ts @@ -46,7 +46,10 @@ describe('WebhookServer', () => { const pathPrefix = config.getEnv(`endpoints.${key}`); manager.getWebhookMethods.mockResolvedValueOnce(['GET']); - const response = await agent.options(`/${pathPrefix}/abcd`).set('origin', corsOrigin); + const response = await agent + .options(`/${pathPrefix}/abcd`) + .set('origin', corsOrigin) + .set('access-control-request-method', 'GET'); expect(response.statusCode).toEqual(204); expect(response.body).toEqual({}); expect(response.headers['access-control-allow-origin']).toEqual(corsOrigin); @@ -60,7 +63,10 @@ describe('WebhookServer', () => { mockResponse({ test: true }, { key: 'value ' }), ); - const response = await agent.get(`/${pathPrefix}/abcd`).set('origin', corsOrigin); + const response = await agent + .get(`/${pathPrefix}/abcd`) + .set('origin', corsOrigin) + .set('access-control-request-method', 'GET'); expect(response.statusCode).toEqual(200); expect(response.body).toEqual({ test: true }); expect(response.headers['access-control-allow-origin']).toEqual(corsOrigin); diff --git a/packages/nodes-base/nodes/Webhook/Webhook.node.ts b/packages/nodes-base/nodes/Webhook/Webhook.node.ts index 191d2af7f5a59..677ae1b7c44f5 100644 --- a/packages/nodes-base/nodes/Webhook/Webhook.node.ts +++ b/packages/nodes-base/nodes/Webhook/Webhook.node.ts @@ -45,6 +45,7 @@ export class Webhook extends Node { defaults: { name: 'Webhook', }, + supportsCORS: true, triggerPanel: { header: '', executionsHelp: { diff --git a/packages/workflow/src/Interfaces.ts b/packages/workflow/src/Interfaces.ts index 4b35633ec80a7..06b634083496a 100644 --- a/packages/workflow/src/Interfaces.ts +++ b/packages/workflow/src/Interfaces.ts @@ -1594,7 +1594,8 @@ export interface INodeTypeDescription extends INodeTypeBaseDescription { properties: INodeProperties[]; credentials?: INodeCredentialDescription[]; maxNodes?: number; // How many nodes of that type can be created in a workflow - polling?: boolean; + polling?: true | undefined; + supportsCORS?: true | undefined; requestDefaults?: DeclarativeRestApiSettings.HttpRequestOptions; requestOperations?: IN8nRequestOperations; hooks?: { diff --git a/packages/workflow/src/NodeHelpers.ts b/packages/workflow/src/NodeHelpers.ts index 23350559d1e53..ae46dc2fdb247 100644 --- a/packages/workflow/src/NodeHelpers.ts +++ b/packages/workflow/src/NodeHelpers.ts @@ -236,7 +236,7 @@ export const cronNodeOptions: INodePropertyCollection[] = [ }, ]; -const specialNodeParameters: INodeProperties[] = [ +const commonPollingParameters: INodeProperties[] = [ { displayName: 'Poll Times', name: 'pollTimes', @@ -252,12 +252,28 @@ const specialNodeParameters: INodeProperties[] = [ }, ]; +const commonCORSParameters: INodeProperties[] = [ + { + displayName: 'Allowed Origins (CORS)', + name: 'allowedOrigins', + type: 'string', + default: '*', + description: 'The origin(s) to allow cross-origin non-preflight requests from in a browser', + }, +]; + /** * Apply special parameters which should be added to nodeTypes depending on their type or configuration */ export function applySpecialNodeParameters(nodeType: INodeType): void { - if (nodeType.description.polling === true) { - nodeType.description.properties.unshift(...specialNodeParameters); + const { properties, polling, supportsCORS } = nodeType.description; + if (polling) { + properties.unshift(...commonPollingParameters); + } + if (nodeType.webhook && supportsCORS) { + const optionsProperty = properties.find(({ name }) => name === 'options'); + if (optionsProperty) optionsProperty.options!.push(...commonCORSParameters); + else properties.push(...commonCORSParameters); } } From 77bc8ecd4b1552f7253bc1348087db518ce7ce07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milorad=20FIlipovi=C4=87?= Date: Thu, 23 Nov 2023 10:14:34 +0100 Subject: [PATCH 04/61] feat(editor): Show avatars for users currently working on the same workflow (#7763) This PR introduces the following changes: - New Vue stores: `collaborationStore` and `pushConnectionStore` - Front-end push connection handling overhaul: Keep only a singe connection open and handle it from the new store - Add user avatars in the editor header when there are multiple users working on the same workflow - Sending a heartbeat event to back-end service periodically to confirm user is still active - Back-end overhauls (authored by @tomi): - Implementing a cleanup procedure that removes inactive users - Refactoring collaboration service current implementation --------- Co-authored-by: Tomi Turtiainen <10324676+tomi@users.noreply.github.com> --- packages/cli/src/Server.ts | 4 + .../collaboration/collaboration.service.ts | 17 ++ .../src/collaboration/collaboration.state.ts | 17 ++ packages/cli/src/push/index.ts | 9 +- .../collaboration/collaboration.state.test.ts | 61 +++++++ .../src/components/N8nUserStack/UserStack.vue | 16 +- packages/editor-ui/src/App.vue | 3 + packages/editor-ui/src/Interface.ts | 14 +- .../MainHeader/CollaborationPane.vue | 81 +++++++++ .../src/components/MainHeader/MainHeader.vue | 5 - .../components/MainHeader/WorkflowDetails.vue | 76 +++++---- .../__tests__/CollaborationPane.test.ts | 135 +++++++++++++++ packages/editor-ui/src/constants.ts | 12 ++ .../editor-ui/src/mixins/pushConnection.ts | 112 ++----------- .../src/stores/collaboration.store.ts | 53 ++++++ packages/editor-ui/src/stores/index.ts | 2 + .../src/stores/pushConnection.store.ts | 154 ++++++++++++++++++ packages/editor-ui/src/views/NodeView.vue | 31 +++- 18 files changed, 654 insertions(+), 148 deletions(-) create mode 100644 packages/cli/test/unit/collaboration/collaboration.state.test.ts create mode 100644 packages/editor-ui/src/components/MainHeader/CollaborationPane.vue create mode 100644 packages/editor-ui/src/components/__tests__/CollaborationPane.test.ts create mode 100644 packages/editor-ui/src/stores/collaboration.store.ts create mode 100644 packages/editor-ui/src/stores/pushConnection.store.ts diff --git a/packages/cli/src/Server.ts b/packages/cli/src/Server.ts index 5ea20083d67e4..b7e6b512504c7 100644 --- a/packages/cli/src/Server.ts +++ b/packages/cli/src/Server.ts @@ -116,6 +116,7 @@ import { UserService } from './services/user.service'; import { OrchestrationController } from './controllers/orchestration.controller'; import { WorkflowHistoryController } from './workflows/workflowHistory/workflowHistory.controller.ee'; import { InvitationController } from './controllers/invitation.controller'; +import { CollaborationService } from './collaboration/collaboration.service'; const exec = promisify(callbackExec); @@ -138,6 +139,8 @@ export class Server extends AbstractServer { private postHog: PostHogClient; + private collaborationService: CollaborationService; + constructor() { super('main'); @@ -233,6 +236,7 @@ export class Server extends AbstractServer { .then(async (workflow) => Container.get(InternalHooks).onServerStarted(diagnosticInfo, workflow?.createdAt), ); + this.collaborationService = Container.get(CollaborationService); } private async registerControllers(ignoredEndpoints: Readonly) { diff --git a/packages/cli/src/collaboration/collaboration.service.ts b/packages/cli/src/collaboration/collaboration.service.ts index 4181995c0fcca..b19378e372ab6 100644 --- a/packages/cli/src/collaboration/collaboration.service.ts +++ b/packages/cli/src/collaboration/collaboration.service.ts @@ -1,5 +1,6 @@ import type { Workflow } from 'n8n-workflow'; import { Service } from 'typedi'; +import config from '@/config'; import { Push } from '../push'; import { Logger } from '@/Logger'; import type { WorkflowClosedMessage, WorkflowOpenedMessage } from './collaboration.message'; @@ -8,6 +9,13 @@ import { UserService } from '../services/user.service'; import type { IActiveWorkflowUsersChanged } from '../Interfaces'; import type { OnPushMessageEvent } from '@/push/types'; import { CollaborationState } from '@/collaboration/collaboration.state'; +import { TIME } from '@/constants'; + +/** + * After how many minutes of inactivity a user should be removed + * as being an active user of a workflow. + */ +const INACTIVITY_CLEAN_UP_TIME_IN_MS = 15 * TIME.MINUTE; /** * Service for managing collaboration feature between users. E.g. keeping @@ -28,6 +36,14 @@ export class CollaborationService { return; } + const isMultiMainSetup = config.get('multiMainSetup.enabled'); + if (isMultiMainSetup) { + // TODO: We should support collaboration in multi-main setup as well + // This requires using redis as the state store instead of in-memory + logger.warn('Collaboration features are disabled because multi-main setup is enabled.'); + return; + } + this.push.on('message', async (event: OnPushMessageEvent) => { try { await this.handleUserMessage(event.userId, event.msg); @@ -53,6 +69,7 @@ export class CollaborationService { const { workflowId } = msg; this.state.addActiveWorkflowUser(workflowId, userId); + this.state.cleanInactiveUsers(workflowId, INACTIVITY_CLEAN_UP_TIME_IN_MS); await this.sendWorkflowUsersChangedMessage(workflowId); } diff --git a/packages/cli/src/collaboration/collaboration.state.ts b/packages/cli/src/collaboration/collaboration.state.ts index 02dff0d450fe5..530a529650068 100644 --- a/packages/cli/src/collaboration/collaboration.state.ts +++ b/packages/cli/src/collaboration/collaboration.state.ts @@ -59,4 +59,21 @@ export class CollaborationState { return [...workflowState.values()]; } + + /** + * Removes all users that have not been seen in a given time + */ + cleanInactiveUsers(workflowId: Workflow['id'], inactivityCleanUpTimeInMs: number) { + const activeUsers = this.state.activeUsersByWorkflowId.get(workflowId); + if (!activeUsers) { + return; + } + + const now = Date.now(); + for (const user of activeUsers.values()) { + if (now - user.lastSeen.getTime() > inactivityCleanUpTimeInMs) { + activeUsers.delete(user.userId); + } + } + } } diff --git a/packages/cli/src/push/index.ts b/packages/cli/src/push/index.ts index 451a0e2e79790..0cbd28da3cb57 100644 --- a/packages/cli/src/push/index.ts +++ b/packages/cli/src/push/index.ts @@ -30,6 +30,14 @@ export class Push extends EventEmitter { private backend = useWebSockets ? Container.get(WebSocketPush) : Container.get(SSEPush); + constructor() { + super(); + + if (useWebSockets) { + this.backend.on('message', (msg) => this.emit('message', msg)); + } + } + handleRequest(req: SSEPushRequest | WebSocketPushRequest, res: PushResponse) { const { userId, @@ -37,7 +45,6 @@ export class Push extends EventEmitter { } = req; if (req.ws) { (this.backend as WebSocketPush).add(sessionId, userId, req.ws); - this.backend.on('message', (msg) => this.emit('message', msg)); } else if (!useWebSockets) { (this.backend as SSEPush).add(sessionId, userId, { req, res }); } else { diff --git a/packages/cli/test/unit/collaboration/collaboration.state.test.ts b/packages/cli/test/unit/collaboration/collaboration.state.test.ts new file mode 100644 index 0000000000000..b390bf9ad98b8 --- /dev/null +++ b/packages/cli/test/unit/collaboration/collaboration.state.test.ts @@ -0,0 +1,61 @@ +import { TIME } from '@/constants'; +import { CollaborationState } from '@/collaboration/collaboration.state'; + +const origDate = global.Date; + +const mockDateFactory = (currentDate: string) => { + return class CustomDate extends origDate { + constructor() { + super(currentDate); + } + } as DateConstructor; +}; + +describe('CollaborationState', () => { + let collaborationState: CollaborationState; + + beforeEach(() => { + collaborationState = new CollaborationState(); + }); + + describe('cleanInactiveUsers', () => { + const workflowId = 'workflow'; + + it('should remove inactive users', () => { + // Setup + global.Date = mockDateFactory('2023-01-01T00:00:00.000Z'); + collaborationState.addActiveWorkflowUser(workflowId, 'inactiveUser'); + + global.Date = mockDateFactory('2023-01-01T00:30:00.000Z'); + collaborationState.addActiveWorkflowUser(workflowId, 'activeUser'); + + // Act: Clean inactive users + jest + .spyOn(global.Date, 'now') + .mockReturnValue(new origDate('2023-01-01T00:35:00.000Z').getTime()); + collaborationState.cleanInactiveUsers(workflowId, 10 * TIME.MINUTE); + + // Assert: The inactive user should be removed + expect(collaborationState.getActiveWorkflowUsers(workflowId)).toEqual([ + { userId: 'activeUser', lastSeen: new origDate('2023-01-01T00:30:00.000Z') }, + ]); + }); + + it('should not remove active users', () => { + // Setup: Add an active user to the state + global.Date = mockDateFactory('2023-01-01T00:30:00.000Z'); + collaborationState.addActiveWorkflowUser(workflowId, 'activeUser'); + + // Act: Clean inactive users + jest + .spyOn(global.Date, 'now') + .mockReturnValue(new origDate('2023-01-01T00:35:00.000Z').getTime()); + collaborationState.cleanInactiveUsers(workflowId, 10 * TIME.MINUTE); + + // Assert: The active user should still be present + expect(collaborationState.getActiveWorkflowUsers(workflowId)).toEqual([ + { userId: 'activeUser', lastSeen: new origDate('2023-01-01T00:30:00.000Z') }, + ]); + }); + }); +}); diff --git a/packages/design-system/src/components/N8nUserStack/UserStack.vue b/packages/design-system/src/components/N8nUserStack/UserStack.vue index a437006d09a42..d95397d13475b 100644 --- a/packages/design-system/src/components/N8nUserStack/UserStack.vue +++ b/packages/design-system/src/components/N8nUserStack/UserStack.vue @@ -75,26 +75,31 @@ const menuHeight = computed(() => { :max-height="menuHeight" popper-class="user-stack-popper" > -
+
+{{ hiddenUsersCount }}
diff --git a/packages/editor-ui/src/views/SetupWorkflowFromTemplateView/SetupTemplateFormStep.vue b/packages/editor-ui/src/views/SetupWorkflowFromTemplateView/SetupTemplateFormStep.vue index 59753687506e2..5db317c1f9c84 100644 --- a/packages/editor-ui/src/views/SetupWorkflowFromTemplateView/SetupTemplateFormStep.vue +++ b/packages/editor-ui/src/views/SetupWorkflowFromTemplateView/SetupTemplateFormStep.vue @@ -77,16 +77,16 @@ const onCredentialDeselected = () => {