From 14752bbf1c705d9570e0f99d9232cf17ba2974f5 Mon Sep 17 00:00:00 2001 From: Elias Meire Date: Wed, 25 Sep 2024 12:01:38 +0200 Subject: [PATCH] Change getCredentials type inference --- ....timestamp-1727257659612-c95ed92583391.mjs | 54 +++++++ packages/core/src/NodeExecuteFunctions.ts | 22 +-- .../nodes-base/credentials/Ftp.credentials.ts | 45 ++++-- .../credentials/Sftp.credentials.ts | 73 +++++++--- .../credentials/StrapiApi.credentials.ts | 40 +++--- .../credentials/StrapiTokenApi.credentials.ts | 16 ++- packages/nodes-base/nodes/Ftp/Ftp.node.ts | 72 +++++----- .../nodes-base/nodes/Strapi/Strapi.node.ts | 9 +- packages/nodes-base/types.d.ts | 24 ---- .../src/CredentialSchema/CredentialSchema.ts | 78 ++++------ packages/workflow/src/Interfaces.ts | 7 +- packages/workflow/src/index.ts | 5 +- .../CredentialSchema.test.ts | 2 +- pnpm-lock.yaml | 135 +----------------- 14 files changed, 263 insertions(+), 319 deletions(-) create mode 100644 packages/@n8n/chat/vite.config.mts.timestamp-1727257659612-c95ed92583391.mjs delete mode 100644 packages/nodes-base/types.d.ts rename packages/workflow/{src/CredentialSchema => test}/CredentialSchema.test.ts (97%) diff --git a/packages/@n8n/chat/vite.config.mts.timestamp-1727257659612-c95ed92583391.mjs b/packages/@n8n/chat/vite.config.mts.timestamp-1727257659612-c95ed92583391.mjs new file mode 100644 index 0000000000..732eb95595 --- /dev/null +++ b/packages/@n8n/chat/vite.config.mts.timestamp-1727257659612-c95ed92583391.mjs @@ -0,0 +1,54 @@ +// vite.config.mts +import { defineConfig } from "file:///Users/elias/projects/github/n8n-io/n8n/node_modules/.pnpm/vite@5.4.6_@types+node@18.16.16_sass@1.64.1_terser@5.16.1/node_modules/vite/dist/node/index.js"; +import { resolve } from "path"; +import vue from "file:///Users/elias/projects/github/n8n-io/n8n/node_modules/.pnpm/@vitejs+plugin-vue@5.1.4_vite@5.4.6_@types+node@18.16.16_sass@1.64.1_terser@5.16.1__vue@3.4.21_typescript@5.6.2_/node_modules/@vitejs/plugin-vue/dist/index.mjs"; +import icons from "file:///Users/elias/projects/github/n8n-io/n8n/node_modules/.pnpm/unplugin-icons@0.19.0_@vue+compiler-sfc@3.4.21_vue-template-compiler@2.7.14/node_modules/unplugin-icons/dist/vite.js"; +import dts from "file:///Users/elias/projects/github/n8n-io/n8n/node_modules/.pnpm/vite-plugin-dts@3.9.1_@types+node@18.16.16_rollup@4.22.2_typescript@5.6.2_vite@5.4.6_@types+n_rcaikbew5ptk64olpe4bf2iruu/node_modules/vite-plugin-dts/dist/index.mjs"; +var __vite_injected_original_dirname = "/Users/elias/projects/github/n8n-io/n8n/packages/@n8n/chat"; +var includeVue = process.env.INCLUDE_VUE === "true"; +var srcPath = resolve(__vite_injected_original_dirname, "src"); +var vite_config_default = defineConfig({ + plugins: [ + vue(), + icons({ + compiler: "vue3", + autoInstall: true + }), + dts() + ], + resolve: { + alias: { + "@": srcPath, + "@n8n/chat": srcPath, + lodash: "lodash-es" + } + }, + define: { + "process.env.NODE_ENV": process.env.NODE_ENV ? `"${process.env.NODE_ENV}"` : '"development"' + }, + build: { + emptyOutDir: !includeVue, + lib: { + entry: resolve(__vite_injected_original_dirname, "src", "index.ts"), + name: "N8nChat", + fileName: (format) => includeVue ? `chat.bundle.${format}.js` : `chat.${format}.js` + }, + rollupOptions: { + // make sure to externalize deps that shouldn't be bundled + // into your library + external: includeVue ? [] : ["vue"], + output: { + exports: "named", + // Provide global variables to use in the UMD build + // for externalized deps + globals: includeVue ? {} : { + vue: "Vue" + } + } + } + } +}); +export { + vite_config_default as default +}; +//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcubXRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyJjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZGlybmFtZSA9IFwiL1VzZXJzL2VsaWFzL3Byb2plY3RzL2dpdGh1Yi9uOG4taW8vbjhuL3BhY2thZ2VzL0BuOG4vY2hhdFwiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiL1VzZXJzL2VsaWFzL3Byb2plY3RzL2dpdGh1Yi9uOG4taW8vbjhuL3BhY2thZ2VzL0BuOG4vY2hhdC92aXRlLmNvbmZpZy5tdHNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfaW1wb3J0X21ldGFfdXJsID0gXCJmaWxlOi8vL1VzZXJzL2VsaWFzL3Byb2plY3RzL2dpdGh1Yi9uOG4taW8vbjhuL3BhY2thZ2VzL0BuOG4vY2hhdC92aXRlLmNvbmZpZy5tdHNcIjtpbXBvcnQgeyBkZWZpbmVDb25maWcgfSBmcm9tICd2aXRlJztcbmltcG9ydCB7IHJlc29sdmUgfSBmcm9tICdwYXRoJztcbmltcG9ydCB2dWUgZnJvbSAnQHZpdGVqcy9wbHVnaW4tdnVlJztcbmltcG9ydCBpY29ucyBmcm9tICd1bnBsdWdpbi1pY29ucy92aXRlJztcbmltcG9ydCBkdHMgZnJvbSAndml0ZS1wbHVnaW4tZHRzJztcblxuY29uc3QgaW5jbHVkZVZ1ZSA9IHByb2Nlc3MuZW52LklOQ0xVREVfVlVFID09PSAndHJ1ZSc7XG5jb25zdCBzcmNQYXRoID0gcmVzb2x2ZShfX2Rpcm5hbWUsICdzcmMnKTtcblxuLy8gaHR0cHM6Ly92aXRlanMuZGV2L2NvbmZpZy9cbmV4cG9ydCBkZWZhdWx0IGRlZmluZUNvbmZpZyh7XG5cdHBsdWdpbnM6IFtcblx0XHR2dWUoKSxcblx0XHRpY29ucyh7XG5cdFx0XHRjb21waWxlcjogJ3Z1ZTMnLFxuXHRcdFx0YXV0b0luc3RhbGw6IHRydWUsXG5cdFx0fSksXG5cdFx0ZHRzKCksXG5cdF0sXG5cdHJlc29sdmU6IHtcblx0XHRhbGlhczoge1xuXHRcdFx0J0AnOiBzcmNQYXRoLFxuXHRcdFx0J0BuOG4vY2hhdCc6IHNyY1BhdGgsXG5cdFx0XHRsb2Rhc2g6ICdsb2Rhc2gtZXMnLFxuXHRcdH0sXG5cdH0sXG5cdGRlZmluZToge1xuXHRcdCdwcm9jZXNzLmVudi5OT0RFX0VOVic6IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gYFwiJHtwcm9jZXNzLmVudi5OT0RFX0VOVn1cImAgOiAnXCJkZXZlbG9wbWVudFwiJyxcblx0fSxcblx0YnVpbGQ6IHtcblx0XHRlbXB0eU91dERpcjogIWluY2x1ZGVWdWUsXG5cdFx0bGliOiB7XG5cdFx0XHRlbnRyeTogcmVzb2x2ZShfX2Rpcm5hbWUsICdzcmMnLCAnaW5kZXgudHMnKSxcblx0XHRcdG5hbWU6ICdOOG5DaGF0Jyxcblx0XHRcdGZpbGVOYW1lOiAoZm9ybWF0KSA9PiAoaW5jbHVkZVZ1ZSA/IGBjaGF0LmJ1bmRsZS4ke2Zvcm1hdH0uanNgIDogYGNoYXQuJHtmb3JtYXR9LmpzYCksXG5cdFx0fSxcblx0XHRyb2xsdXBPcHRpb25zOiB7XG5cdFx0XHQvLyBtYWtlIHN1cmUgdG8gZXh0ZXJuYWxpemUgZGVwcyB0aGF0IHNob3VsZG4ndCBiZSBidW5kbGVkXG5cdFx0XHQvLyBpbnRvIHlvdXIgbGlicmFyeVxuXHRcdFx0ZXh0ZXJuYWw6IGluY2x1ZGVWdWUgPyBbXSA6IFsndnVlJ10sXG5cdFx0XHRvdXRwdXQ6IHtcblx0XHRcdFx0ZXhwb3J0czogJ25hbWVkJyxcblx0XHRcdFx0Ly8gUHJvdmlkZSBnbG9iYWwgdmFyaWFibGVzIHRvIHVzZSBpbiB0aGUgVU1EIGJ1aWxkXG5cdFx0XHRcdC8vIGZvciBleHRlcm5hbGl6ZWQgZGVwc1xuXHRcdFx0XHRnbG9iYWxzOiBpbmNsdWRlVnVlXG5cdFx0XHRcdFx0PyB7fVxuXHRcdFx0XHRcdDoge1xuXHRcdFx0XHRcdFx0XHR2dWU6ICdWdWUnLFxuXHRcdFx0XHRcdFx0fSxcblx0XHRcdH0sXG5cdFx0fSxcblx0fSxcbn0pO1xuIl0sCiAgIm1hcHBpbmdzIjogIjtBQUFrVyxTQUFTLG9CQUFvQjtBQUMvWCxTQUFTLGVBQWU7QUFDeEIsT0FBTyxTQUFTO0FBQ2hCLE9BQU8sV0FBVztBQUNsQixPQUFPLFNBQVM7QUFKaEIsSUFBTSxtQ0FBbUM7QUFNekMsSUFBTSxhQUFhLFFBQVEsSUFBSSxnQkFBZ0I7QUFDL0MsSUFBTSxVQUFVLFFBQVEsa0NBQVcsS0FBSztBQUd4QyxJQUFPLHNCQUFRLGFBQWE7QUFBQSxFQUMzQixTQUFTO0FBQUEsSUFDUixJQUFJO0FBQUEsSUFDSixNQUFNO0FBQUEsTUFDTCxVQUFVO0FBQUEsTUFDVixhQUFhO0FBQUEsSUFDZCxDQUFDO0FBQUEsSUFDRCxJQUFJO0FBQUEsRUFDTDtBQUFBLEVBQ0EsU0FBUztBQUFBLElBQ1IsT0FBTztBQUFBLE1BQ04sS0FBSztBQUFBLE1BQ0wsYUFBYTtBQUFBLE1BQ2IsUUFBUTtBQUFBLElBQ1Q7QUFBQSxFQUNEO0FBQUEsRUFDQSxRQUFRO0FBQUEsSUFDUCx3QkFBd0IsUUFBUSxJQUFJLFdBQVcsSUFBSSxRQUFRLElBQUksUUFBUSxNQUFNO0FBQUEsRUFDOUU7QUFBQSxFQUNBLE9BQU87QUFBQSxJQUNOLGFBQWEsQ0FBQztBQUFBLElBQ2QsS0FBSztBQUFBLE1BQ0osT0FBTyxRQUFRLGtDQUFXLE9BQU8sVUFBVTtBQUFBLE1BQzNDLE1BQU07QUFBQSxNQUNOLFVBQVUsQ0FBQyxXQUFZLGFBQWEsZUFBZSxNQUFNLFFBQVEsUUFBUSxNQUFNO0FBQUEsSUFDaEY7QUFBQSxJQUNBLGVBQWU7QUFBQTtBQUFBO0FBQUEsTUFHZCxVQUFVLGFBQWEsQ0FBQyxJQUFJLENBQUMsS0FBSztBQUFBLE1BQ2xDLFFBQVE7QUFBQSxRQUNQLFNBQVM7QUFBQTtBQUFBO0FBQUEsUUFHVCxTQUFTLGFBQ04sQ0FBQyxJQUNEO0FBQUEsVUFDQSxLQUFLO0FBQUEsUUFDTjtBQUFBLE1BQ0g7QUFBQSxJQUNEO0FBQUEsRUFDRDtBQUNELENBQUM7IiwKICAibmFtZXMiOiBbXQp9Cg== diff --git a/packages/core/src/NodeExecuteFunctions.ts b/packages/core/src/NodeExecuteFunctions.ts index 0d37dde2b3..714f28eae5 100644 --- a/packages/core/src/NodeExecuteFunctions.ts +++ b/packages/core/src/NodeExecuteFunctions.ts @@ -102,6 +102,7 @@ import type { SSHTunnelFunctions, SchedulingFunctions, AiEvent, + ICredentialType, } from 'n8n-workflow'; import { NodeConnectionType, @@ -1995,7 +1996,7 @@ export function getAdditionalKeys( export async function getCredentials( workflow: Workflow, node: INode, - type: string, + credType: string | (new () => ICredentialType), additionalData: IWorkflowExecuteAdditionalData, mode: WorkflowExecuteMode, executeData?: IExecuteData, @@ -2004,6 +2005,7 @@ export async function getCredentials { + const type = typeof credType === 'string' ? credType : credType.name; // Get the NodeType as it has the information if the credentials are required const nodeType = workflow.nodeTypes.getByNameAndVersion(node.type, node.typeVersion); if (nodeType === undefined) { @@ -3496,8 +3498,10 @@ export function getExecutePollFunctions( }, getMode: () => mode, getActivationMode: () => activation, - getCredentials: async (type) => - await getCredentials(workflow, node, type, additionalData, mode), + getCredentials: async (type: string | (new () => ICredentialType)) => { + const typeString = typeof type === 'string' ? type : type.name; + return await getCredentials(workflow, node, typeString, additionalData, mode); + }, getNodeParameter: ( parameterName: string, fallbackValue?: any, @@ -3560,7 +3564,7 @@ export function getExecuteTriggerFunctions( }, getMode: () => mode, getActivationMode: () => activation, - getCredentials: async (type) => + getCredentials: async (type: string | (new () => ICredentialType)) => await getCredentials(workflow, node, type, additionalData, mode), getNodeParameter: ( parameterName: string, @@ -3620,7 +3624,7 @@ export function getExecuteFunctions( ...getCommonWorkflowFunctions(workflow, node, additionalData), ...executionCancellationFunctions(abortSignal), getMode: () => mode, - getCredentials: async (type, itemIndex) => + getCredentials: async (type: string | (new () => ICredentialType), itemIndex: number) => await getCredentials( workflow, node, @@ -3948,7 +3952,7 @@ export function getExecuteSingleFunctions( getContext(type: ContextType): IContextObject { return NodeHelpers.getContext(runExecutionData, type, node); }, - getCredentials: async (type) => + getCredentials: async (type: string | (new () => ICredentialType)) => await getCredentials( workflow, node, @@ -4088,7 +4092,7 @@ export function getLoadOptionsFunctions( return ((workflow: Workflow, node: INode, path: string) => { return { ...getCommonWorkflowFunctions(workflow, node, additionalData), - getCredentials: async (type) => + getCredentials: async (type: string | (new () => ICredentialType)) => await getCredentials(workflow, node, type, additionalData, 'internal'), getCurrentNodeParameter: ( parameterPath: string, @@ -4169,7 +4173,7 @@ export function getExecuteHookFunctions( return ((workflow: Workflow, node: INode) => { return { ...getCommonWorkflowFunctions(workflow, node, additionalData), - getCredentials: async (type) => + getCredentials: async (type: string | (new () => ICredentialType)) => await getCredentials(workflow, node, type, additionalData, mode), getMode: () => mode, getActivationMode: () => activation, @@ -4243,7 +4247,7 @@ export function getExecuteWebhookFunctions( } return additionalData.httpRequest.body; }, - getCredentials: async (type) => + getCredentials: async (type: string | (new () => ICredentialType)) => await getCredentials(workflow, node, type, additionalData, mode), getHeaderData(): IncomingHttpHeaders { if (additionalData.httpRequest === undefined) { diff --git a/packages/nodes-base/credentials/Ftp.credentials.ts b/packages/nodes-base/credentials/Ftp.credentials.ts index 8c6a6e6af7..0592a8ecc4 100644 --- a/packages/nodes-base/credentials/Ftp.credentials.ts +++ b/packages/nodes-base/credentials/Ftp.credentials.ts @@ -1,14 +1,4 @@ -import type { ICredentialType } from 'n8n-workflow'; -import { CredentialSchema, type InferCredentialSchema } from '../utils/CredentialSchema'; - -const ftpCredentialSchema = CredentialSchema.create({ - host: CredentialSchema.string({ label: 'Host', placeholder: 'localhost' }), - port: CredentialSchema.number({ label: 'Port', default: 21 }), - username: CredentialSchema.string({ label: 'Username', optional: true }), - password: CredentialSchema.password({ optional: true }), -}); - -export type FtpCredentialSchema = InferCredentialSchema; +import type { ICredentialType, INodeProperties } from 'n8n-workflow'; export class Ftp implements ICredentialType { name = 'ftp'; @@ -17,5 +7,36 @@ export class Ftp implements ICredentialType { documentationUrl = 'ftp'; - properties = ftpCredentialSchema.toNodeProperties(); + properties: INodeProperties[] = [ + { + displayName: 'Host', + name: 'host', + required: true, + type: 'string', + default: '', + placeholder: 'localhost', + }, + { + displayName: 'Port', + name: 'port', + required: true, + type: 'number', + default: 21, + }, + { + displayName: 'Username', + name: 'username', + type: 'string', + default: '', + }, + { + displayName: 'Password', + name: 'password', + type: 'string', + typeOptions: { + password: true, + }, + default: '', + }, + ]; } diff --git a/packages/nodes-base/credentials/Sftp.credentials.ts b/packages/nodes-base/credentials/Sftp.credentials.ts index 56a0a9501d..3238097d6d 100644 --- a/packages/nodes-base/credentials/Sftp.credentials.ts +++ b/packages/nodes-base/credentials/Sftp.credentials.ts @@ -1,23 +1,4 @@ -import type { ICredentialType } from 'n8n-workflow'; -import { CredentialSchema, type InferCredentialSchema } from '../utils/CredentialSchema'; - -const sftpCredentialSchema = CredentialSchema.create({ - host: CredentialSchema.string({ label: 'Host', placeholder: 'localhost' }), - port: CredentialSchema.number({ label: 'Port', default: 22 }), - username: CredentialSchema.string({ label: 'Username' }), - password: CredentialSchema.password(), - privateKey: CredentialSchema.password({ - label: 'Private Key', - description: - 'String that contains a private key for either key-based or hostbased user authentication (OpenSSH format)', - }), - passphrase: CredentialSchema.password({ - label: 'Passphrase', - description: 'For an encrypted private key, this is the passphrase used to decrypt it', - }), -}); - -export type SftpCredentialSchema = InferCredentialSchema; +import type { ICredentialType, INodeProperties } from 'n8n-workflow'; export class Sftp implements ICredentialType { name = 'sftp'; @@ -26,5 +7,55 @@ export class Sftp implements ICredentialType { documentationUrl = 'ftp'; - properties = sftpCredentialSchema.toNodeProperties(); + properties: INodeProperties[] = [ + { + displayName: 'Host', + name: 'host', + required: true, + type: 'string', + default: '', + }, + { + displayName: 'Port', + name: 'port', + required: true, + type: 'number', + default: 22, + }, + { + displayName: 'Username', + name: 'username', + required: true, + type: 'string', + default: '', + }, + { + displayName: 'Password', + name: 'password', + type: 'string', + typeOptions: { + password: true, + }, + default: '', + }, + { + displayName: 'Private Key', + name: 'privateKey', + type: 'string', + typeOptions: { password: true }, + default: '', + description: + 'String that contains a private key for either key-based or hostbased user authentication (OpenSSH format)', + }, + { + displayName: 'Passphrase', + name: 'passphrase', + typeOptions: { + password: true, + }, + type: 'string', + default: '', + description: 'For an encrypted private key, this is the passphrase used to decrypt it', + }, + ]; } diff --git a/packages/nodes-base/credentials/StrapiApi.credentials.ts b/packages/nodes-base/credentials/StrapiApi.credentials.ts index b3b66ad752..8de2a0b0ef 100644 --- a/packages/nodes-base/credentials/StrapiApi.credentials.ts +++ b/packages/nodes-base/credentials/StrapiApi.credentials.ts @@ -1,47 +1,39 @@ -import type { ICredentialType } from "n8n-workflow"; -import { - CredentialSchema, - type InferCredentialSchema, -} from "../utils/CredentialSchema"; +import { type ICredentialType, CredentialSchema, type InferCredentialSchema } from 'n8n-workflow'; export const strapiApiCredentialSchema = CredentialSchema.create({ - notice: CredentialSchema.notice( - "Make sure you are using a user account not an admin account", - ), - email: CredentialSchema.email({ placeholder: "name@email.com" }), + notice: CredentialSchema.notice('Make sure you are using a user account not an admin account'), + email: CredentialSchema.email({ placeholder: 'name@email.com' }), password: CredentialSchema.password(), url: CredentialSchema.url({ - placeholder: "https://api.example.com", + placeholder: 'https://api.example.com', }), apiVersion: CredentialSchema.options({ - label: "API Version", - description: "The version of api to be used", + label: 'API Version', + description: 'The version of api to be used', options: [ { - label: "Version 4", - value: "v4", - description: "API version supported by Strapi 4", + label: 'Version 4', + value: 'v4', + description: 'API version supported by Strapi 4', }, { - label: "Version 3", - value: "v3", + label: 'Version 3', + value: 'v3', default: true, - description: "API version supported by Strapi 3", + description: 'API version supported by Strapi 3', }, ], }), }); -export type StrapiApiCredential = InferCredentialSchema< - typeof strapiApiCredentialSchema ->; +export type StrapiApiCredential = InferCredentialSchema; export class StrapiApi implements ICredentialType { - name = "strapiApi"; + name = 'strapiApi'; - displayName = "Strapi API"; + displayName = 'Strapi API'; - documentationUrl = "strapi"; + documentationUrl = 'strapi'; properties = strapiApiCredentialSchema.toNodeProperties(); diff --git a/packages/nodes-base/credentials/StrapiTokenApi.credentials.ts b/packages/nodes-base/credentials/StrapiTokenApi.credentials.ts index 52ee5dde44..dab768bed2 100644 --- a/packages/nodes-base/credentials/StrapiTokenApi.credentials.ts +++ b/packages/nodes-base/credentials/StrapiTokenApi.credentials.ts @@ -1,7 +1,11 @@ -import type { IAuthenticateGeneric, ICredentialTestRequest, ICredentialType } from 'n8n-workflow'; -import { CredentialSchema, type InferCredentialSchema } from '../utils/CredentialSchema'; +import { + CredentialSchema, + type ICredentialType, + type IAuthenticateGeneric, + type ICredentialTestRequest, +} from 'n8n-workflow'; -export const strapiTokenApiCredential = CredentialSchema.create({ +const strapiTokenApiCredentialSchema = CredentialSchema.create({ apiToken: CredentialSchema.password({ label: 'API Token' }), url: CredentialSchema.url({ placeholder: 'https://api.example.com' }), apiVersion: CredentialSchema.options({ @@ -23,8 +27,6 @@ export const strapiTokenApiCredential = CredentialSchema.create({ }), }); -export type StrapiTokenApiCredential = InferCredentialSchema; - export class StrapiTokenApi implements ICredentialType { name = 'strapiTokenApi'; @@ -32,7 +34,9 @@ export class StrapiTokenApi implements ICredentialType { documentationUrl = 'strapi'; - properties = strapiTokenApiCredential.toNodeProperties(); + properties = strapiTokenApiCredentialSchema.toNodeProperties(); + + schema = strapiTokenApiCredentialSchema; authenticate: IAuthenticateGeneric = { type: 'generic', diff --git a/packages/nodes-base/nodes/Ftp/Ftp.node.ts b/packages/nodes-base/nodes/Ftp/Ftp.node.ts index 34cd000a8f..99d9e4b77d 100644 --- a/packages/nodes-base/nodes/Ftp/Ftp.node.ts +++ b/packages/nodes-base/nodes/Ftp/Ftp.node.ts @@ -7,6 +7,7 @@ import ftpClient from 'promise-ftp'; import sftpClient from 'ssh2-sftp-client'; import { BINARY_ENCODING, NodeApiError, NodeConnectionType } from 'n8n-workflow'; import type { + ICredentialDataDecryptedObject, ICredentialsDecrypted, ICredentialTestFunctions, IDataObject, @@ -17,8 +18,6 @@ import type { INodeTypeDescription, JsonObject, } from 'n8n-workflow'; -import type { FtpCredentialSchema } from '@credentials/Ftp.credentials'; -import type { SftpCredentialSchema } from '@credentials/Sftp.credentials'; import { formatPrivateKey, generatePairedItemData } from '@utils/utilities'; interface ReturnFtpItem { @@ -440,14 +439,14 @@ export class Ftp implements INodeType { this: ICredentialTestFunctions, credential: ICredentialsDecrypted, ): Promise { - const credentials = credential.data as FtpCredentialSchema; + const credentials = credential.data as ICredentialDataDecryptedObject; const ftp = new ftpClient(); try { await ftp.connect({ - host: credentials.host, - port: credentials.port, - user: credentials.username, - password: credentials.password, + host: credentials.host as string, + port: credentials.port as number, + user: credentials.username as string, + password: credentials.password as string, }); } catch (error) { await ftp.end(); @@ -466,24 +465,24 @@ export class Ftp implements INodeType { this: ICredentialTestFunctions, credential: ICredentialsDecrypted, ): Promise { - const credentials = credential.data as SftpCredentialSchema; + const credentials = credential.data as ICredentialDataDecryptedObject; const sftp = new sftpClient(); try { if (credentials.privateKey) { await sftp.connect({ - host: credentials.host, - port: credentials.port, - username: credentials.username, - password: credentials.password || undefined, - privateKey: formatPrivateKey(credentials.privateKey), - passphrase: credentials.passphrase, + host: credentials.host as string, + port: credentials.port as number, + username: credentials.username as string, + password: (credentials.password as string) || undefined, + privateKey: formatPrivateKey(credentials.privateKey as string), + passphrase: credentials.passphrase as string | undefined, }); } else { await sftp.connect({ - host: credentials.host, - port: credentials.port, - username: credentials.username, - password: credentials.password, + host: credentials.host as string, + port: credentials.port as number, + username: credentials.username as string, + password: credentials.password as string, }); } } catch (error) { @@ -507,9 +506,14 @@ export class Ftp implements INodeType { let returnItems: INodeExecutionData[] = []; const operation = this.getNodeParameter('operation', 0); + let credentials: ICredentialDataDecryptedObject | undefined = undefined; const protocol = this.getNodeParameter('protocol', 0) as string; - const credentials = await this.getCredentials(protocol === 'sftp' ? 'sftp' : 'ftp'); + if (protocol === 'sftp') { + credentials = await this.getCredentials('sftp'); + } else { + credentials = await this.getCredentials('ftp'); + } let ftp: ftpClient; let sftp: sftpClient; @@ -517,30 +521,30 @@ export class Ftp implements INodeType { try { if (protocol === 'sftp') { sftp = new sftpClient(); - if ('privateKey' in credentials && credentials.privateKey) { + if (credentials.privateKey) { await sftp.connect({ - host: credentials.host, - port: credentials.port, - username: credentials.username, - password: credentials.password || undefined, - privateKey: formatPrivateKey(credentials.privateKey), - passphrase: credentials.passphrase, + host: credentials.host as string, + port: credentials.port as number, + username: credentials.username as string, + password: (credentials.password as string) || undefined, + privateKey: formatPrivateKey(credentials.privateKey as string), + passphrase: credentials.passphrase as string | undefined, }); } else { await sftp.connect({ - host: credentials.host, - port: credentials.port, - username: credentials.username, - password: credentials.password, + host: credentials.host as string, + port: credentials.port as number, + username: credentials.username as string, + password: credentials.password as string, }); } } else { ftp = new ftpClient(); await ftp.connect({ - host: credentials.host, - port: credentials.port, - user: credentials.username, - password: credentials.password, + host: credentials.host as string, + port: credentials.port as number, + user: credentials.username as string, + password: credentials.password as string, }); } } catch (error) { diff --git a/packages/nodes-base/nodes/Strapi/Strapi.node.ts b/packages/nodes-base/nodes/Strapi/Strapi.node.ts index b1792ac7a2..3f7b0f8bd8 100644 --- a/packages/nodes-base/nodes/Strapi/Strapi.node.ts +++ b/packages/nodes-base/nodes/Strapi/Strapi.node.ts @@ -1,8 +1,8 @@ import type { - IExecuteFunctions, ICredentialsDecrypted, ICredentialTestFunctions, IDataObject, + IExecuteFunctions, INodeCredentialTestResult, INodeExecutionData, INodeType, @@ -19,8 +19,9 @@ import { validateJSON, } from './GenericFunctions'; +import { StrapiApi, type StrapiApiCredential } from '@credentials/StrapiApi.credentials'; +import { StrapiTokenApi } from '../../credentials/StrapiTokenApi.credentials'; import { entryFields, entryOperations } from './EntryDescription'; -import type { StrapiApiCredential } from '@credentials/StrapiApi.credentials'; export class Strapi implements INodeType { description: INodeTypeDescription = { @@ -148,10 +149,10 @@ export class Strapi implements INodeType { if (authenticationMethod === 'password') { const { jwt } = await getToken.call(this); - apiVersion = (await this.getCredentials('strapiApi')).apiVersion; + apiVersion = (await this.getCredentials(StrapiApi)).apiVersion; headers.Authorization = `Bearer ${jwt}`; } else { - apiVersion = (await this.getCredentials('strapiTokenApi')).apiVersion; + apiVersion = (await this.getCredentials(StrapiTokenApi)).apiVersion; } for (let i = 0; i < length; i++) { diff --git a/packages/nodes-base/types.d.ts b/packages/nodes-base/types.d.ts deleted file mode 100644 index 8fa358138b..0000000000 --- a/packages/nodes-base/types.d.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { FtpCredentialSchema } from './credentials/Ftp.credentials'; -import type { SftpCredentialSchema } from './credentials/Sftp.credentials'; -import type { StrapiApiCredential } from './credentials/StrapiApi.credentials'; -import type { StrapiTokenApiCredential } from './credentials/StrapiTokenApi.credentials'; - -type CredentialSchemaMap = { - strapiApi: StrapiApiCredential; - strapiTokenApi: StrapiTokenApiCredential; - ftp: FtpCredentialSchema; - sftp: SftpCredentialSchema; -}; - -declare module 'n8n-workflow' { - interface FunctionsBase { - getCredentials( - type: Type, - itemIndex?: number, - ): Promise< - Type extends keyof CredentialSchemaMap - ? CredentialSchemaMap[Type] - : ICredentialDataDecryptedObject - >; - } -} diff --git a/packages/workflow/src/CredentialSchema/CredentialSchema.ts b/packages/workflow/src/CredentialSchema/CredentialSchema.ts index e40839d080..57b92035a7 100644 --- a/packages/workflow/src/CredentialSchema/CredentialSchema.ts +++ b/packages/workflow/src/CredentialSchema/CredentialSchema.ts @@ -1,8 +1,9 @@ -import z, { type ZodOptional, type ZodType } from "zod"; -import type { INodeProperties } from "@/Interfaces"; +import z, { type ZodOptional, type ZodType } from 'zod'; + +import type { INodeProperties } from '@/Interfaces'; function isObject(value: unknown): value is object { - return typeof value === "object" && value !== null && !Array.isArray(value); + return typeof value === 'object' && value !== null && !Array.isArray(value); } function removeUndefinedProperties(obj: T): T { @@ -40,25 +41,19 @@ class CredentialSchemaRootObject< ); } - getProperty(key: K): T[K]["metadata"] { + getProperty(key: K): T[K]['metadata'] { return this.shape[key].metadata; } toNodeProperties() { - return Object.entries(this.shape).map(([key, schema]) => - schema.toNodeProperties(key), - ); + return Object.entries(this.shape).map(([key, schema]) => schema.toNodeProperties(key)); } } type ToZodSchemaReturnType< M extends BaseMetadata = BaseMetadata, S extends ZodType | null = ZodType, -> = M["optional"] extends true - ? S extends null - ? null - : ZodOptional> - : S; +> = M['optional'] extends true ? (S extends null ? null : ZodOptional>) : S; abstract class CredentialSchemaProperty< M extends BaseMetadata = BaseMetadata, @@ -82,8 +77,8 @@ abstract class CredentialSchemaProperty< name, displayName: this.metadata.label, description: this.metadata.description, - default: "", - type: "string", + default: '', + type: 'string', }); } } @@ -102,7 +97,7 @@ class CredentialSchemaString< toNodeProperties(name: string): INodeProperties { return removeUndefinedProperties({ ...super.toNodeProperties(name), - type: "string", + type: 'string', placeholder: this.metadata.placeholder, typeOptions: { password: this.metadata.password }, }); @@ -123,7 +118,7 @@ class CredentialSchemaNumber< toNodeProperties(name: string): INodeProperties { return removeUndefinedProperties({ ...super.toNodeProperties(name), - type: "number", + type: 'number', default: this.metadata.default, }); } @@ -145,22 +140,18 @@ class CredentialSchemaOptions< const { options } = this.metadata; return removeUndefinedProperties({ ...super.toNodeProperties(name), - type: "options", + type: 'options', options: options.map((option) => ({ name: option.label, value: option.value, description: option.description, })), - default: - options.find((option) => option.default)?.value ?? options[0].value, + default: options.find((option) => option.default)?.value ?? options[0].value, }); } } -class CredentialSchemaNotice extends CredentialSchemaProperty< - BaseMetadata, - null -> { +class CredentialSchemaNotice extends CredentialSchemaProperty { constructor(public notice: string) { super({ label: notice }, null); } @@ -168,7 +159,7 @@ class CredentialSchemaNotice extends CredentialSchemaProperty< toNodeProperties(name: string): INodeProperties { return { ...super.toNodeProperties(name), - type: "notice", + type: 'notice', }; } } @@ -208,18 +199,18 @@ type Zodify< M extends BaseMetadata, S extends ZodType | null, T extends CredentialSchemaProperty, -> = ReturnType extends z.ZodType - ? ReturnType - : never; +> = ReturnType extends z.ZodType ? ReturnType : never; type ZodifyObject< M extends BaseMetadata, S extends ZodType | null, T extends { [k: string]: CredentialSchemaProperty }, > = { - [K in keyof T as ReturnType extends z.ZodType - ? K - : never]: Zodify; + [K in keyof T as ReturnType extends z.ZodType ? K : never]: Zodify< + M, + S, + T[K] + >; }; type Optional = Omit & Partial>; @@ -233,11 +224,11 @@ export const CredentialSchema = { return new CredentialSchemaRootObject(shape); }, - password(options: Omit, "password"> = {}) { + password(options: Omit, 'password'> = {}) { return new CredentialSchemaString( { password: true, - label: "Password", + label: 'Password', ...options, }, z.string(), @@ -251,24 +242,18 @@ export const CredentialSchema = { number(options: M) { return new CredentialSchemaNumber(options, z.number()); }, - url(options: Optional = {}) { - return new CredentialSchemaString( - { label: "URL", ...options }, - z.string().url(), - ); + url(options: Optional = {}) { + return new CredentialSchemaString({ label: 'URL', ...options }, z.string().url()); }, - email(options: Optional = {}) { - return new CredentialSchemaString( - { label: "Email", ...options }, - z.string().email(), - ); + email(options: Optional = {}) { + return new CredentialSchemaString({ label: 'Email', ...options }, z.string().email()); }, options>(options: M) { return new CredentialSchemaOptions( options, z.enum( options.options.map((option) => option.value) as NonEmptyArray< - M["options"][number]["value"] + M['options'][number]['value'] >, ), ); @@ -278,11 +263,8 @@ export const CredentialSchema = { }, }; -export type TCredentialSchema = CredentialSchemaRootObject< - BaseMetadata, - ZodType | null ->; +export type TCredentialSchema = CredentialSchemaRootObject; export type InferCredentialSchema = z.infer< - ReturnType + ReturnType >; diff --git a/packages/workflow/src/Interfaces.ts b/packages/workflow/src/Interfaces.ts index 7e819c33be..59b281ac75 100644 --- a/packages/workflow/src/Interfaces.ts +++ b/packages/workflow/src/Interfaces.ts @@ -13,6 +13,7 @@ import type { SecureContextOptions } from 'tls'; import type { URLSearchParams } from 'url'; import type { CODE_EXECUTION_MODES, CODE_LANGUAGES, LOG_LEVELS } from './Constants'; +import type { InferCredentialSchema, TCredentialSchema } from './CredentialSchema/CredentialSchema'; import type { IDeferredPromise } from './DeferredPromise'; import type { ExecutionCancelledError } from './errors'; import type { ExpressionError } from './errors/expression.error'; @@ -864,12 +865,12 @@ export interface FunctionsBase { type: string, itemIndex?: number, ): Promise; - getCredentials( + getCredentials ICredentialType>( type: T, itemIndex?: number, ): Promise< - T['schema'] extends TCredentialSchema - ? InferCredentialSchema + InstanceType['schema'] extends TCredentialSchema + ? InferCredentialSchema['schema']> : ICredentialDataDecryptedObject >; getCredentialsProperties(type: string): INodeProperties[]; diff --git a/packages/workflow/src/index.ts b/packages/workflow/src/index.ts index 935e2a16b3..c6ba2999b2 100644 --- a/packages/workflow/src/index.ts +++ b/packages/workflow/src/index.ts @@ -51,10 +51,7 @@ export { ExpressionExtensions } from './Extensions'; export * as ExpressionParser from './Extensions/ExpressionParser'; export { NativeMethods } from './NativeMethods'; export * from './NodeParameters/FilterParameter'; -export { - CredentialSchema, - InferCredentialSchema, -} from './CredentialSchema/CredentialSchema'; +export * from './CredentialSchema/CredentialSchema'; export type { DocMetadata, diff --git a/packages/workflow/src/CredentialSchema/CredentialSchema.test.ts b/packages/workflow/test/CredentialSchema.test.ts similarity index 97% rename from packages/workflow/src/CredentialSchema/CredentialSchema.test.ts rename to packages/workflow/test/CredentialSchema.test.ts index f285507c69..40ca5ffe31 100644 --- a/packages/workflow/src/CredentialSchema/CredentialSchema.test.ts +++ b/packages/workflow/test/CredentialSchema.test.ts @@ -1,4 +1,4 @@ -import { CredentialSchema } from '../CredentialSchema'; +import { CredentialSchema } from '../src/CredentialSchema/CredentialSchema'; describe('CredentialSchema', () => { test('should convert Strapi credential to node properties', () => { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7d7a598b3a..9ffe672383 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1871,10 +1871,13 @@ importers: xml2js: specifier: 'catalog:' version: 0.6.2 + zod: + specifier: 'catalog:' + version: 3.23.8 devDependencies: '@langchain/core': specifier: 'catalog:' - version: 0.2.31(langchain@0.2.18(axios@1.7.4)(openai@4.58.0))(openai@4.58.0) + version: 0.2.31(langchain@0.2.18(axios@1.7.4)(openai@4.58.0(zod@3.23.8)))(openai@4.58.0(zod@3.23.8)) '@types/deep-equal': specifier: ^1.0.1 version: 1.0.1 @@ -15085,41 +15088,6 @@ snapshots: - langchain - openai - '@langchain/core@0.2.31(langchain@0.2.18(axios@1.7.4)(openai@4.58.0))(openai@4.58.0(zod@3.23.8))': - dependencies: - ansi-styles: 5.2.0 - camelcase: 6.3.0 - decamelize: 1.2.0 - js-tiktoken: 1.0.12 - langsmith: 0.1.51(@langchain/core@0.2.31(langchain@0.2.18(axios@1.7.4)(openai@4.58.0))(openai@4.58.0(zod@3.23.8)))(langchain@0.2.18(axios@1.7.4)(openai@4.58.0))(openai@4.58.0(zod@3.23.8)) - mustache: 4.2.0 - p-queue: 6.6.2 - p-retry: 4.6.2 - uuid: 10.0.0 - zod: 3.23.8 - zod-to-json-schema: 3.23.2(zod@3.23.8) - transitivePeerDependencies: - - langchain - - openai - optional: true - - '@langchain/core@0.2.31(langchain@0.2.18(axios@1.7.4)(openai@4.58.0))(openai@4.58.0)': - dependencies: - ansi-styles: 5.2.0 - camelcase: 6.3.0 - decamelize: 1.2.0 - js-tiktoken: 1.0.12 - langsmith: 0.1.51(@langchain/core@0.2.31(langchain@0.2.18(axios@1.7.4)(openai@4.58.0))(openai@4.58.0))(langchain@0.2.18(axios@1.7.4)(openai@4.58.0))(openai@4.58.0) - mustache: 4.2.0 - p-queue: 6.6.2 - p-retry: 4.6.2 - uuid: 10.0.0 - zod: 3.23.8 - zod-to-json-schema: 3.23.2(zod@3.23.8) - transitivePeerDependencies: - - langchain - - openai - '@langchain/core@0.2.31(langchain@0.2.18(svs4mugxvnip77thgyjbfeyt2a))(openai@4.58.0(encoding@0.1.13)(zod@3.23.8))': dependencies: ansi-styles: 5.2.0 @@ -15230,20 +15198,7 @@ snapshots: dependencies: '@langchain/core': 0.2.31(langchain@0.2.18(axios@1.7.4)(openai@4.58.0(zod@3.23.8)))(openai@4.58.0(zod@3.23.8)) js-tiktoken: 1.0.12 - openai: 4.58.0(zod@3.23.8) - zod: 3.23.8 - zod-to-json-schema: 3.23.2(zod@3.23.8) - transitivePeerDependencies: - - encoding - - langchain - - supports-color - optional: true - - '@langchain/openai@0.2.10(langchain@0.2.18(axios@1.7.4)(openai@4.58.0))': - dependencies: - '@langchain/core': 0.2.31(langchain@0.2.18(axios@1.7.4)(openai@4.58.0))(openai@4.58.0(zod@3.23.8)) - js-tiktoken: 1.0.12 - openai: 4.58.0(zod@3.23.8) + openai: 4.58.0(encoding@0.1.13)(zod@3.23.8) zod: 3.23.8 zod-to-json-schema: 3.23.2(zod@3.23.8) transitivePeerDependencies: @@ -15289,15 +15244,6 @@ snapshots: - openai optional: true - '@langchain/textsplitters@0.0.3(langchain@0.2.18(axios@1.7.4)(openai@4.58.0))(openai@4.58.0)': - dependencies: - '@langchain/core': 0.2.31(langchain@0.2.18(axios@1.7.4)(openai@4.58.0))(openai@4.58.0) - js-tiktoken: 1.0.12 - transitivePeerDependencies: - - langchain - - openai - optional: true - '@langchain/textsplitters@0.0.3(langchain@0.2.18(svs4mugxvnip77thgyjbfeyt2a))(openai@4.58.0(encoding@0.1.13)(zod@3.23.8))': dependencies: '@langchain/core': 0.2.31(langchain@0.2.18(svs4mugxvnip77thgyjbfeyt2a))(openai@4.58.0(encoding@0.1.13)(zod@3.23.8)) @@ -22087,30 +22033,6 @@ snapshots: - supports-color optional: true - langchain@0.2.18(axios@1.7.4)(openai@4.58.0): - dependencies: - '@langchain/core': 0.2.31(langchain@0.2.18(axios@1.7.4)(openai@4.58.0))(openai@4.58.0) - '@langchain/openai': 0.2.10(langchain@0.2.18(axios@1.7.4)(openai@4.58.0)) - '@langchain/textsplitters': 0.0.3(langchain@0.2.18(axios@1.7.4)(openai@4.58.0))(openai@4.58.0) - binary-extensions: 2.2.0 - js-tiktoken: 1.0.12 - js-yaml: 4.1.0 - jsonpointer: 5.0.1 - langsmith: 0.1.51(@langchain/core@0.2.31(langchain@0.2.18(axios@1.7.4)(openai@4.58.0))(openai@4.58.0))(langchain@0.2.18(axios@1.7.4)(openai@4.58.0))(openai@4.58.0) - openapi-types: 12.1.3 - p-retry: 4.6.2 - uuid: 10.0.0 - yaml: 2.3.4 - zod: 3.23.8 - zod-to-json-schema: 3.23.2(zod@3.23.8) - optionalDependencies: - axios: 1.7.4(debug@4.3.6) - transitivePeerDependencies: - - encoding - - openai - - supports-color - optional: true - langchain@0.2.18(svs4mugxvnip77thgyjbfeyt2a): dependencies: '@langchain/core': 0.2.31(langchain@0.2.18(svs4mugxvnip77thgyjbfeyt2a))(openai@4.58.0(encoding@0.1.13)(zod@3.23.8)) @@ -22184,34 +22106,7 @@ snapshots: optionalDependencies: '@langchain/core': 0.2.31(langchain@0.2.18(axios@1.7.4)(openai@4.58.0(zod@3.23.8)))(openai@4.58.0(zod@3.23.8)) langchain: 0.2.18(axios@1.7.4)(openai@4.58.0(zod@3.23.8)) - openai: 4.58.0(zod@3.23.8) - - langsmith@0.1.51(@langchain/core@0.2.31(langchain@0.2.18(axios@1.7.4)(openai@4.58.0))(openai@4.58.0(zod@3.23.8)))(langchain@0.2.18(axios@1.7.4)(openai@4.58.0))(openai@4.58.0(zod@3.23.8)): - dependencies: - '@types/uuid': 10.0.0 - commander: 10.0.1 - p-queue: 6.6.2 - p-retry: 4.6.2 - semver: 7.6.0 - uuid: 10.0.0 - optionalDependencies: - '@langchain/core': 0.2.31(langchain@0.2.18(axios@1.7.4)(openai@4.58.0))(openai@4.58.0(zod@3.23.8)) - langchain: 0.2.18(axios@1.7.4)(openai@4.58.0) - openai: 4.58.0(zod@3.23.8) - optional: true - - langsmith@0.1.51(@langchain/core@0.2.31(langchain@0.2.18(axios@1.7.4)(openai@4.58.0))(openai@4.58.0))(langchain@0.2.18(axios@1.7.4)(openai@4.58.0))(openai@4.58.0): - dependencies: - '@types/uuid': 10.0.0 - commander: 10.0.1 - p-queue: 6.6.2 - p-retry: 4.6.2 - semver: 7.6.0 - uuid: 10.0.0 - optionalDependencies: - '@langchain/core': 0.2.31(langchain@0.2.18(axios@1.7.4)(openai@4.58.0))(openai@4.58.0) - langchain: 0.2.18(axios@1.7.4)(openai@4.58.0) - openai: 4.58.0(zod@3.23.8) + openai: 4.58.0(encoding@0.1.13)(zod@3.23.8) langsmith@0.1.51(@langchain/core@0.2.31(langchain@0.2.18(svs4mugxvnip77thgyjbfeyt2a))(openai@4.58.0(encoding@0.1.13)(zod@3.23.8)))(langchain@0.2.18(svs4mugxvnip77thgyjbfeyt2a))(openai@4.58.0(encoding@0.1.13)(zod@3.23.8)): dependencies: @@ -23542,24 +23437,6 @@ snapshots: - encoding - supports-color - openai@4.58.0(zod@3.23.8): - dependencies: - '@types/node': 18.16.16 - '@types/node-fetch': 2.6.4 - '@types/qs': 6.9.15 - abort-controller: 3.0.0 - agentkeepalive: 4.2.1 - form-data-encoder: 1.7.2 - formdata-node: 4.4.1 - node-fetch: 2.7.0(encoding@0.1.13) - qs: 6.11.0 - optionalDependencies: - zod: 3.23.8 - transitivePeerDependencies: - - encoding - - supports-color - optional: true - openapi-sampler@1.4.0: dependencies: '@types/json-schema': 7.0.15