diff --git a/components/sftp/actions/upload-file/upload-file.mjs b/components/sftp/actions/upload-file/upload-file.mjs index d1c436fda12de..8b49f960c74ee 100644 --- a/components/sftp/actions/upload-file/upload-file.mjs +++ b/components/sftp/actions/upload-file/upload-file.mjs @@ -6,7 +6,7 @@ export default { key: "sftp-upload-file", name: "Upload File", description: "Uploads a file or string in UTF-8 format to the SFTP server. [See the documentation](https://github.com/theophilusx/ssh2-sftp-client#org99d1b64)", - version: "0.2.0", + version: "0.3.0", type: "action", props: { app, diff --git a/components/sftp/package.json b/components/sftp/package.json index c3473e5f21706..135bce7b847bd 100644 --- a/components/sftp/package.json +++ b/components/sftp/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/sftp", - "version": "0.3.8", + "version": "0.4.0", "description": "Pipedream SFTP Components", "main": "sftp.app.mjs", "keywords": [ @@ -10,8 +10,8 @@ "homepage": "https://pipedream.com/apps/sftp", "author": "Pipedream (https://pipedream.com/)", "dependencies": { - "@pipedream/platform": "^1.2.0", - "ssh2-sftp-client": "^8.1.0" + "@pipedream/platform": "^3.0.3", + "ssh2-sftp-client": "^11.0.0" }, "gitHead": "e12480b94cc03bed4808ebc6b13e7fdb3a1ba535", "publishConfig": { diff --git a/components/sftp/sftp.app.mjs b/components/sftp/sftp.app.mjs index cfec450fccfe3..9382150a8a095 100644 --- a/components/sftp/sftp.app.mjs +++ b/components/sftp/sftp.app.mjs @@ -20,23 +20,27 @@ export default { }, }, methods: { - async connect() { + getConfig() { const { host, username, privateKey, } = this.$auth; - const config = { + return { host, username, privateKey, }; - + }, + async connect() { const sftp = new Client(); - await sftp.connect(config); + await sftp.connect(this.getConfig()); return sftp; }, + async disconnect(sftp) { + await sftp.end(); + }, async put({ buffer, remotePath, diff --git a/components/sftp/sources/common/base.mjs b/components/sftp/sources/common/base.mjs deleted file mode 100644 index 0cb6e6d4d92f6..0000000000000 --- a/components/sftp/sources/common/base.mjs +++ /dev/null @@ -1,125 +0,0 @@ -import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform"; - -export default { - props: { - timer: { - type: "$.interface.timer", - default: { - intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, - }, - }, - db: "$.service.db", - rootDirectory: { - label: "Root directory", - description: "Root directory to be watched. example: `/public`", - type: "string", - default: "/", - }, - maxDepth: { - label: "Maximum watcher depth", - description: "Watch all subdirectories within of the root directory, considering the selected maximum depth.", - type: "integer", - min: 0, - }, - }, - methods: { - setFiles(files) { - this.db.set("files", files); - }, - getFiles() { - return this.db.get("files") || []; - }, - getChangesWithEvent(currentFiles, previousFiles) { - const fileChanges = []; - // deleted file detection; - for (const prvFile of previousFiles) { - const file = currentFiles.find((p) => p.path === prvFile.path); - if (!file) { - fileChanges.push({ - ...prvFile, - event: "deleted", - }); - } - } - // created, updated file detection; - for (const file of currentFiles) { - const prvFile = previousFiles.find((p) => p.path === file.path); - if (prvFile) { - // unchanged files (checking size and last update time) - if (prvFile.size === file.size && prvFile.modifyTime === file.modifyTime) { - continue; - } - // file has changed - fileChanges.push({ - ...file, - event: "updated", - }); - } else { - // new file detection - fileChanges.push({ - ...file, - event: "created", - }); - } - } - return fileChanges; - }, - async listDirectories(sftp, parent, currDepth) { - const files = await sftp.list(parent); - return files.filter((file) => file.type === "d") - .map((directory) => ({ - ...directory, - parent, - path: `${parent}/${directory.name}`, - depth: currDepth, - })); - }, - async listDirectoriesDeep(sftp, parent, maxDepth, currDepth) { - if (currDepth > maxDepth) { - return []; - } - const nextDepth = currDepth + 1; - const rootDirectories = await this.listDirectories(sftp, parent, currDepth); - const childrenDirectories = []; - for (const item of rootDirectories) { - const path = `${parent}/${item.name}`; - const directories = await this.listDirectoriesDeep(sftp, path, maxDepth, nextDepth); - childrenDirectories.push(...directories); - } - rootDirectories.push(...childrenDirectories); - return rootDirectories; - }, - async listAllFilesFromDirectories(sftp, directories) { - const allFiles = []; - for (const directory of directories) { - const listingResult = await sftp.list(directory.path); - const files = listingResult.filter((file) => file.type !== "d") - .map((file) => ({ - ...file, - directory: directory.path, - path: `${directory.path}/${file.name}`, - depth: directory.depth || 0, - })); - allFiles.push(...files); - } - return allFiles; - }, - validateRootDirectory(rootDirectory) { - if (!rootDirectory) { - throw new Error("Must provide root directory"); - } - if (!rootDirectory.startsWith("/")) { - throw new Error("The root directory must to be the absolute path and start with a slash, such as: '/public'"); - } - }, - emitEvents(events) { - for (const fileChangeEvent of events) { - this.$emit(fileChangeEvent, { - id: `${fileChangeEvent.event}|${fileChangeEvent.path}|${fileChangeEvent.size}|${fileChangeEvent.modifyTime}`, - summary: `${fileChangeEvent.event} ${fileChangeEvent.path}`, - ts: new Date(fileChangeEvent.modifyTime), - }); - } - }, - }, -}; diff --git a/components/sftp/sources/watch-remote-directory/watch-remote-directory.mjs b/components/sftp/sources/watch-remote-directory/watch-remote-directory.mjs index e783c48da7600..15222cdd85127 100644 --- a/components/sftp/sources/watch-remote-directory/watch-remote-directory.mjs +++ b/components/sftp/sources/watch-remote-directory/watch-remote-directory.mjs @@ -1,15 +1,16 @@ -import sftpApp from "../../sftp.app.mjs"; +import { createHash } from "crypto"; +import app from "../../sftp.app.mjs"; import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform"; export default { key: "sftp-watch-remote-directory", name: "New Remote Directory Watcher", description: "Emit new events when files get created, changed or deleted from a remote directory. [See the docs](https://github.com/theophilusx/ssh2-sftp-client#orgfac43d1)", - version: "0.0.4", + version: "0.1.0", type: "source", dedupe: "unique", props: { - sftpApp, + app, timer: { type: "$.interface.timer", default: { @@ -121,9 +122,15 @@ export default { } }, getEventId(event) { - return `${event.event}|${event.path}|${event.size}|${event.modifyTime}`; + const uniqueIdentifier = + createHash("md5") + .update(event.path + event.modifyTime) + .digest("hex"); + return `${event.event}|${event.path}|${event.size}|${event.modifyTime}|${uniqueIdentifier}`; }, emitEvents(events) { + // sort events by modification time in ascending order + events.sort((a, b) => a.modifyTime - b.modifyTime); for (const fileChangeEvent of events) { this.$emit(fileChangeEvent, { id: this.getEventId(fileChangeEvent), @@ -132,17 +139,11 @@ export default { }); } }, - async connect() { - return await this.sftpApp.connect(); - }, - async disconnect(sftp) { - await sftp.end(); - }, }, async run() { this.validateRootDirectory(this.rootDirectory); - const sftp = await this.connect(); + const sftp = await this.app.connect(); let directories = [ { @@ -159,6 +160,6 @@ export default { this.emitEvents(filesChangesWithEvent); this.setFiles(currentFiles); - await this.disconnect(sftp); + await this.app.disconnect(sftp); }, }; diff --git a/components/sftp_password_based_auth/actions/upload-file/upload-file.mjs b/components/sftp_password_based_auth/actions/upload-file/upload-file.mjs index 914690f87b314..0b303821db04f 100644 --- a/components/sftp_password_based_auth/actions/upload-file/upload-file.mjs +++ b/components/sftp_password_based_auth/actions/upload-file/upload-file.mjs @@ -1,44 +1,14 @@ -// legacy_hash_id: a_YEikdQ -import Client from "ssh2-sftp-client"; +import utils from "../../common/utils.mjs"; +import component from "../../../sftp/actions/upload-file/upload-file.mjs"; export default { + ...component, + props: utils.buildAppProps({ + component, + }), key: "sftp_password_based_auth-upload-file", - name: "Upload String as File", - description: "Uploads a UTF-8 string as a file on an SFTP server", - version: "0.1.1", + name: "Upload File (Password Auth)", + description: "Uploads a file or string in UTF-8 format to the SFTP server. [See the documentation](https://github.com/theophilusx/ssh2-sftp-client#org99d1b64)", + version: "0.2.0", type: "action", - props: { - sftp_password_based_auth: { - type: "app", - app: "sftp_password_based_auth", - }, - data: { - type: "string", - description: "A UTF-8 string to upload as a file on the remote server.", - }, - remotePath: { - type: "string", - label: "Remote Path", - description: "The path to the remote file to be created on the server.", - }, - }, - async run({ $ }) { - const { - host, - username, - password, - } = this.sftp_password_based_auth.$auth; - - const config = { - host, - username, - password, - }; - - const sftp = new Client(); - - await sftp.connect(config); - $.export("putResponse", await sftp.put(Buffer.from(this.data), this.remotePath)); - await sftp.end(); - }, }; diff --git a/components/sftp_password_based_auth/common/utils.mjs b/components/sftp_password_based_auth/common/utils.mjs new file mode 100644 index 0000000000000..86d009918da0f --- /dev/null +++ b/components/sftp_password_based_auth/common/utils.mjs @@ -0,0 +1,79 @@ +import app from "../sftp_password_based_auth.app.mjs"; + +function buildPropDefinitions({ + app = {}, props = {}, +}) { + return Object.entries(props) + .reduce((newProps, [ + key, + prop, + ]) => { + if (!prop.propDefinition) { + return Object.assign(newProps, { + [key]: prop, + }); + } + + const [ + , ...propDefinitionItems + ] = prop.propDefinition; + + return Object.assign(newProps, { + [key]: Object.assign(prop, { + propDefinition: [ + app, + ...propDefinitionItems, + ], + }), + }); + }, {}); +} + +function getPropsOnly({ + component, omitProps = [], appLabel, addedProps = {}, +} = {}) { + const { + // eslint-disable-next-line no-unused-vars + [appLabel]: appProp, + ...props + } = component.props; + const builtProps = Object.entries(props) + .reduce((reduction, [ + key, + value, + ]) => { + if (omitProps.includes(key)) { + return reduction; + } + return Object.assign(reduction, { + [key]: value, + }); + }, {}); + return { + ...builtProps, + ...addedProps, + }; +} + +function buildAppProps({ + component, omitProps = [], appLabel = "app", addedProps, +} = {}) { + return { + [appLabel]: app, + ...buildPropDefinitions({ + app, + props: getPropsOnly({ + component, + omitProps, + appLabel, + addedProps, + }), + }), + }; +} + +export default { + buildPropDefinitions, + getPropsOnly, + buildAppProps, +}; diff --git a/components/sftp_password_based_auth/package.json b/components/sftp_password_based_auth/package.json index f18cfdcf5e928..db8a9199c6bd6 100644 --- a/components/sftp_password_based_auth/package.json +++ b/components/sftp_password_based_auth/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/sftp_password_based_auth", - "version": "0.3.5", + "version": "0.4.0", "description": "Pipedream SFTP Components", "main": "sftp_password_based_auth.app.mjs", "keywords": [ @@ -9,9 +9,6 @@ ], "homepage": "https://pipedream.com/apps/sftp_password_based_auth", "author": "Pipedream (https://pipedream.com/)", - "dependencies": { - "ssh2-sftp-client": "^8.1.0" - }, "gitHead": "e12480b94cc03bed4808ebc6b13e7fdb3a1ba535", "publishConfig": { "access": "public" diff --git a/components/sftp_password_based_auth/sftp_password_based_auth.app.mjs b/components/sftp_password_based_auth/sftp_password_based_auth.app.mjs index 30e255891c542..3949ded139fa4 100644 --- a/components/sftp_password_based_auth/sftp_password_based_auth.app.mjs +++ b/components/sftp_password_based_auth/sftp_password_based_auth.app.mjs @@ -1,26 +1,23 @@ -import Client from "ssh2-sftp-client"; +import sftpApp from "../sftp/sftp.app.mjs"; export default { + ...sftpApp, type: "app", app: "sftp_password_based_auth", - propDefinitions: {}, methods: { - async connect() { + ...sftpApp.methods, + getConfig() { const { host, username, password, } = this.$auth; - const config = { + return { host, username, password, }; - - const sftp = new Client(); - await sftp.connect(config); - return sftp; }, }, }; diff --git a/components/sftp_password_based_auth/sources/watch-remote-directory/watch-remote-directory.mjs b/components/sftp_password_based_auth/sources/watch-remote-directory/watch-remote-directory.mjs index ce4de2a234326..c4eb43eab4478 100644 --- a/components/sftp_password_based_auth/sources/watch-remote-directory/watch-remote-directory.mjs +++ b/components/sftp_password_based_auth/sources/watch-remote-directory/watch-remote-directory.mjs @@ -1,21 +1,14 @@ -import sftpApp from "../../sftp_password_based_auth.app.mjs"; -import base from "../../../sftp/sources/watch-remote-directory/watch-remote-directory.mjs"; +import utils from "../../common/utils.mjs"; +import component from "../../../sftp/sources/watch-remote-directory/watch-remote-directory.mjs"; export default { - ...base, + ...component, + props: utils.buildAppProps({ + component, + }), key: "sftp_password_based_auth-watch-remote-directory", - name: "New Remote Directory Watcher", + name: "New Remote Directory Watcher (Password Auth)", description: "Emit new events when files get created, changed or deleted from a remote directory. [See the docs](https://github.com/theophilusx/ssh2-sftp-client#orgfac43d1)", - version: "0.0.1", + version: "0.1.0", type: "source", - props: { - ...base.props, - sftpApp, - }, - methods: { - ...base.methods, - async connect() { - return await this.sftpApp.connect(); - }, - }, }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dcdb910c91276..1081eb8dc7f2b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9184,17 +9184,13 @@ importers: components/sftp: dependencies: '@pipedream/platform': - specifier: ^1.2.0 - version: 1.6.6 + specifier: ^3.0.3 + version: 3.0.3 ssh2-sftp-client: - specifier: ^8.1.0 - version: 8.1.0 + specifier: ^11.0.0 + version: 11.0.0 - components/sftp_password_based_auth: - dependencies: - ssh2-sftp-client: - specifier: ^8.1.0 - version: 8.1.0 + components/sftp_password_based_auth: {} components/shadertoy: dependencies: @@ -12253,10 +12249,10 @@ importers: version: 18.3.12 vite: specifier: ^5.4.11 - version: 5.4.11(@types/node@22.10.1) + version: 5.4.11(@types/node@22.10.2) vite-plugin-dts: specifier: ^4.3.0 - version: 4.3.0(@types/node@22.10.1)(rollup@4.27.3)(typescript@5.7.2)(vite@5.4.11(@types/node@22.10.1)) + version: 4.3.0(@types/node@22.10.2)(rollup@4.27.3)(typescript@5.7.2)(vite@5.4.11(@types/node@22.10.2)) packages/connect-react/examples/nextjs: dependencies: @@ -16810,14 +16806,14 @@ packages: '@types/node@18.19.64': resolution: {integrity: sha512-955mDqvO2vFf/oL7V3WiUtiz+BugyX8uVbaT2H8oj3+8dRyH2FLiNdowe7eNqRM7IOIZvzDH76EoAT+gwm6aIQ==} - '@types/node@18.19.67': - resolution: {integrity: sha512-wI8uHusga+0ZugNp0Ol/3BqQfEcCCNfojtO6Oou9iVNGPTL6QNSdnUdqq85fRgIorLhLMuPIKpsN98QE9Nh+KQ==} + '@types/node@18.19.68': + resolution: {integrity: sha512-QGtpFH1vB99ZmTa63K4/FU8twThj4fuVSBkGddTp7uIL/cuoLWIUSL2RcOaigBhfR+hg5pgGkBnkoOxrTVBMKw==} '@types/node@20.17.6': resolution: {integrity: sha512-VEI7OdvK2wP7XHnsuXbAJnEpEkF6NjSN45QJlL4VGqZSXsnicpesdTWsg9RISeSdYd3yeRj/y3k5KGjUXYnFwQ==} - '@types/node@22.10.1': - resolution: {integrity: sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==} + '@types/node@22.10.2': + resolution: {integrity: sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==} '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -24188,9 +24184,9 @@ packages: resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} engines: {node: '>= 0.6'} - ssh2-sftp-client@8.1.0: - resolution: {integrity: sha512-00Ds+QcE7S6R6knE4cgKrvFxsOoAjSS16BSGRkv4n4RNYawyy3Iu9jlRz/nEXxpaVnojf0nn9zp0zATJssRrVw==} - engines: {node: '>=10.24.1'} + ssh2-sftp-client@11.0.0: + resolution: {integrity: sha512-lOjgNYtioYquhtgyHwPryFNhllkuENjvCKkUXo18w/Q4UpEffCnEUBfiOTlwFdKIhG1rhrOGnA6DeKPSF2CP6w==} + engines: {node: '>=18.20.4'} ssh2@1.16.0: resolution: {integrity: sha512-r1X4KsBGedJqo7h8F5c4Ybpcr5RjyP+aWIG007uBPRjmdQWfEiVLzSK71Zji1B9sKxwaCvD8y8cwSkYrlLiRRg==} @@ -28563,7 +28559,7 @@ snapshots: '@definitelytyped/utils@0.1.8': dependencies: '@qiwi/npm-registry-client': 8.9.1 - '@types/node': 18.19.67 + '@types/node': 18.19.68 cachedir: 2.4.0 charm: 1.0.2 minimatch: 9.0.5 @@ -29727,23 +29723,23 @@ snapshots: dependencies: langium: 3.0.0 - '@microsoft/api-extractor-model@7.29.9(@types/node@22.10.1)': + '@microsoft/api-extractor-model@7.29.9(@types/node@22.10.2)': dependencies: '@microsoft/tsdoc': 0.15.0 '@microsoft/tsdoc-config': 0.17.0 - '@rushstack/node-core-library': 5.10.0(@types/node@22.10.1) + '@rushstack/node-core-library': 5.10.0(@types/node@22.10.2) transitivePeerDependencies: - '@types/node' - '@microsoft/api-extractor@7.47.12(@types/node@22.10.1)': + '@microsoft/api-extractor@7.47.12(@types/node@22.10.2)': dependencies: - '@microsoft/api-extractor-model': 7.29.9(@types/node@22.10.1) + '@microsoft/api-extractor-model': 7.29.9(@types/node@22.10.2) '@microsoft/tsdoc': 0.15.0 '@microsoft/tsdoc-config': 0.17.0 - '@rushstack/node-core-library': 5.10.0(@types/node@22.10.1) + '@rushstack/node-core-library': 5.10.0(@types/node@22.10.2) '@rushstack/rig-package': 0.5.3 - '@rushstack/terminal': 0.14.3(@types/node@22.10.1) - '@rushstack/ts-command-line': 4.23.1(@types/node@22.10.1) + '@rushstack/terminal': 0.14.3(@types/node@22.10.2) + '@rushstack/ts-command-line': 4.23.1(@types/node@22.10.2) lodash: 4.17.21 minimatch: 3.0.8 resolve: 1.22.8 @@ -30664,8 +30660,6 @@ snapshots: '@putout/operator-filesystem': 5.0.0(putout@36.13.1(eslint@8.57.1)(typescript@5.6.3)) '@putout/operator-json': 2.2.0 putout: 36.13.1(eslint@8.57.1)(typescript@5.6.3) - transitivePeerDependencies: - - supports-color '@putout/operator-regexp@1.0.0(putout@36.13.1(eslint@8.57.1)(typescript@5.6.3))': dependencies: @@ -31362,7 +31356,7 @@ snapshots: '@rushstack/eslint-patch@1.10.4': {} - '@rushstack/node-core-library@5.10.0(@types/node@22.10.1)': + '@rushstack/node-core-library@5.10.0(@types/node@22.10.2)': dependencies: ajv: 8.13.0 ajv-draft-04: 1.0.0(ajv@8.13.0) @@ -31373,23 +31367,23 @@ snapshots: resolve: 1.22.8 semver: 7.5.4 optionalDependencies: - '@types/node': 22.10.1 + '@types/node': 22.10.2 '@rushstack/rig-package@0.5.3': dependencies: resolve: 1.22.8 strip-json-comments: 3.1.1 - '@rushstack/terminal@0.14.3(@types/node@22.10.1)': + '@rushstack/terminal@0.14.3(@types/node@22.10.2)': dependencies: - '@rushstack/node-core-library': 5.10.0(@types/node@22.10.1) + '@rushstack/node-core-library': 5.10.0(@types/node@22.10.2) supports-color: 8.1.1 optionalDependencies: - '@types/node': 22.10.1 + '@types/node': 22.10.2 - '@rushstack/ts-command-line@4.23.1(@types/node@22.10.1)': + '@rushstack/ts-command-line@4.23.1(@types/node@22.10.2)': dependencies: - '@rushstack/terminal': 0.14.3(@types/node@22.10.1) + '@rushstack/terminal': 0.14.3(@types/node@22.10.2) '@types/argparse': 1.0.38 argparse: 1.0.10 string-argv: 0.3.2 @@ -32430,7 +32424,7 @@ snapshots: dependencies: undici-types: 5.26.5 - '@types/node@18.19.67': + '@types/node@18.19.68': dependencies: undici-types: 5.26.5 @@ -32438,7 +32432,7 @@ snapshots: dependencies: undici-types: 6.19.8 - '@types/node@22.10.1': + '@types/node@22.10.2': dependencies: undici-types: 6.20.0 optional: true @@ -42359,7 +42353,7 @@ snapshots: sqlstring@2.3.3: {} - ssh2-sftp-client@8.1.0: + ssh2-sftp-client@11.0.0: dependencies: concat-stream: 2.0.0 promise-retry: 2.0.1 @@ -43749,9 +43743,9 @@ snapshots: transitivePeerDependencies: - debug - vite-plugin-dts@4.3.0(@types/node@22.10.1)(rollup@4.27.3)(typescript@5.7.2)(vite@5.4.11(@types/node@22.10.1)): + vite-plugin-dts@4.3.0(@types/node@22.10.2)(rollup@4.27.3)(typescript@5.7.2)(vite@5.4.11(@types/node@22.10.2)): dependencies: - '@microsoft/api-extractor': 7.47.12(@types/node@22.10.1) + '@microsoft/api-extractor': 7.47.12(@types/node@22.10.2) '@rollup/pluginutils': 5.1.3(rollup@4.27.3) '@volar/typescript': 2.4.10 '@vue/language-core': 2.1.6(typescript@5.7.2) @@ -43762,19 +43756,19 @@ snapshots: magic-string: 0.30.13 typescript: 5.7.2 optionalDependencies: - vite: 5.4.11(@types/node@22.10.1) + vite: 5.4.11(@types/node@22.10.2) transitivePeerDependencies: - '@types/node' - rollup - supports-color - vite@5.4.11(@types/node@22.10.1): + vite@5.4.11(@types/node@22.10.2): dependencies: esbuild: 0.21.5 postcss: 8.4.49 rollup: 4.27.3 optionalDependencies: - '@types/node': 22.10.1 + '@types/node': 22.10.2 fsevents: 2.3.3 vm2@3.9.19: