Merge pull request #11 from nasyarobby/cursor/ftp-sftp-script-3038
feat(scripts): add remote-fs script for SFTP and FTP access
This commit is contained in:
@@ -17,6 +17,7 @@
|
|||||||
"@fastify/jwt": "^9.1.0",
|
"@fastify/jwt": "^9.1.0",
|
||||||
"@fastify/static": "^8.2.0",
|
"@fastify/static": "^8.2.0",
|
||||||
"axios": "^1.19.0",
|
"axios": "^1.19.0",
|
||||||
|
"basic-ftp": "^6.2.0",
|
||||||
"bcryptjs": "^3.0.2",
|
"bcryptjs": "^3.0.2",
|
||||||
"better-sqlite3": "^13.0.3",
|
"better-sqlite3": "^13.0.3",
|
||||||
"fastify": "^5.12.0",
|
"fastify": "^5.12.0",
|
||||||
@@ -28,6 +29,7 @@
|
|||||||
"nodemailer": "^9.0.5",
|
"nodemailer": "^9.0.5",
|
||||||
"pino": "^10.3.1",
|
"pino": "^10.3.1",
|
||||||
"pino-roll": "^4.0.0",
|
"pino-roll": "^4.0.0",
|
||||||
|
"ssh2-sftp-client": "^12.1.1",
|
||||||
"webdav": "^5.10.0",
|
"webdav": "^5.10.0",
|
||||||
"yaml": "^2.9.0"
|
"yaml": "^2.9.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,11 +18,14 @@ const ALLOWED_MODULES = new Set([
|
|||||||
"@aws-sdk/client-s3",
|
"@aws-sdk/client-s3",
|
||||||
"@aws-sdk/s3-request-presigner",
|
"@aws-sdk/s3-request-presigner",
|
||||||
"axios",
|
"axios",
|
||||||
|
"basic-ftp",
|
||||||
"jsonata",
|
"jsonata",
|
||||||
"mustache",
|
"mustache",
|
||||||
"node-html-parser",
|
"node-html-parser",
|
||||||
|
"node:stream",
|
||||||
"nodemailer",
|
"nodemailer",
|
||||||
"rss-parser",
|
"rss-parser",
|
||||||
|
"ssh2-sftp-client",
|
||||||
"webdav",
|
"webdav",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,521 @@
|
|||||||
|
import SftpClient from "ssh2-sftp-client";
|
||||||
|
import { Client } from "basic-ftp";
|
||||||
|
import { Readable, Writable } from "node:stream";
|
||||||
|
|
||||||
|
const PROTOCOLS = new Set(["ftp", "sftp"]);
|
||||||
|
const ACTIONS = new Set(["list", "read", "write", "delete", "stat", "mkdir", "rename"]);
|
||||||
|
|
||||||
|
function passContext(ctx) {
|
||||||
|
if (ctx?.context != null && typeof ctx.context === "object" && !Array.isArray(ctx.context)) {
|
||||||
|
return { ...ctx.context };
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
function mergeData(data) {
|
||||||
|
if (data != null && typeof data === "object" && !Array.isArray(data)) {
|
||||||
|
return { ...data };
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveProtocol(ctx) {
|
||||||
|
const raw = ctx.config?.protocol ?? ctx.data?.protocol ?? "sftp";
|
||||||
|
if (typeof raw !== "string" || raw.length === 0) {
|
||||||
|
throw new Error("remote-fs: protocol must be a non-empty string");
|
||||||
|
}
|
||||||
|
const protocol = raw.toLowerCase();
|
||||||
|
if (!PROTOCOLS.has(protocol)) {
|
||||||
|
throw new Error(`remote-fs: unsupported protocol "${raw}" (use ftp or sftp)`);
|
||||||
|
}
|
||||||
|
return protocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveAction(ctx) {
|
||||||
|
const raw = ctx.config?.action ?? ctx.data?.action ?? "list";
|
||||||
|
if (typeof raw !== "string" || raw.length === 0) {
|
||||||
|
throw new Error("remote-fs: action must be a non-empty string");
|
||||||
|
}
|
||||||
|
const action = raw.toLowerCase();
|
||||||
|
if (!ACTIONS.has(action)) {
|
||||||
|
throw new Error(`remote-fs: unsupported action "${raw}"`);
|
||||||
|
}
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolvePath(ctx, { required = false, label = "path" } = {}) {
|
||||||
|
const path = ctx.config?.path ?? ctx.data?.path;
|
||||||
|
if (path == null || path === "") {
|
||||||
|
if (required) throw new Error(`remote-fs: ${label} is required`);
|
||||||
|
return ".";
|
||||||
|
}
|
||||||
|
if (typeof path !== "string") {
|
||||||
|
throw new Error(`remote-fs: ${label} must be a string`);
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveHost(ctx) {
|
||||||
|
const host = ctx.config?.host ?? ctx.data?.host;
|
||||||
|
if (typeof host !== "string" || host.length === 0) {
|
||||||
|
throw new Error("remote-fs: host is required (ctx.config.host or ctx.data.host)");
|
||||||
|
}
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolvePort(ctx, protocol) {
|
||||||
|
const raw = ctx.config?.port ?? ctx.data?.port;
|
||||||
|
if (raw == null || raw === "") {
|
||||||
|
return protocol === "sftp" ? 22 : 21;
|
||||||
|
}
|
||||||
|
const port = Number(raw);
|
||||||
|
if (!Number.isFinite(port) || port <= 0) {
|
||||||
|
throw new Error("remote-fs: port must be a positive number");
|
||||||
|
}
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function resolveSecretValue(secretName, label) {
|
||||||
|
if (typeof secretName !== "string" || secretName.length === 0) {
|
||||||
|
throw new Error(`remote-fs: ${label} is required`);
|
||||||
|
}
|
||||||
|
return $secrets.reveal(await $secrets.get(secretName));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function resolveAuth(ctx) {
|
||||||
|
const username =
|
||||||
|
typeof ctx.config?.usernameSecret === "string" && ctx.config.usernameSecret.length > 0
|
||||||
|
? await resolveSecretValue(ctx.config.usernameSecret, "usernameSecret")
|
||||||
|
: (ctx.config?.username ?? ctx.data?.username);
|
||||||
|
if (typeof username !== "string" || username.length === 0) {
|
||||||
|
throw new Error("remote-fs: username is required");
|
||||||
|
}
|
||||||
|
|
||||||
|
let password;
|
||||||
|
if (typeof ctx.config?.passwordSecret === "string" && ctx.config.passwordSecret.length > 0) {
|
||||||
|
password = await resolveSecretValue(ctx.config.passwordSecret, "passwordSecret");
|
||||||
|
} else if (typeof ctx.config?.password === "string") {
|
||||||
|
password = ctx.config.password;
|
||||||
|
} else if (typeof ctx.data?.password === "string") {
|
||||||
|
password = ctx.data.password;
|
||||||
|
}
|
||||||
|
|
||||||
|
let privateKey;
|
||||||
|
if (typeof ctx.config?.privateKeySecret === "string" && ctx.config.privateKeySecret.length > 0) {
|
||||||
|
privateKey = await resolveSecretValue(ctx.config.privateKeySecret, "privateKeySecret");
|
||||||
|
} else if (typeof ctx.config?.privateKey === "string") {
|
||||||
|
privateKey = ctx.config.privateKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
let passphrase;
|
||||||
|
if (typeof ctx.config?.passphraseSecret === "string" && ctx.config.passphraseSecret.length > 0) {
|
||||||
|
passphrase = await resolveSecretValue(ctx.config.passphraseSecret, "passphraseSecret");
|
||||||
|
} else if (typeof ctx.config?.passphrase === "string") {
|
||||||
|
passphrase = ctx.config.passphrase;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!password && !privateKey) {
|
||||||
|
throw new Error(
|
||||||
|
"remote-fs: password or private key is required (passwordSecret/privateKeySecret or inline values)",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { username, password, privateKey, passphrase };
|
||||||
|
}
|
||||||
|
|
||||||
|
function toIsoDate(value) {
|
||||||
|
if (value == null) return null;
|
||||||
|
const date = value instanceof Date ? value : new Date(value);
|
||||||
|
if (Number.isNaN(date.getTime())) return null;
|
||||||
|
return date.toISOString();
|
||||||
|
}
|
||||||
|
|
||||||
|
function joinRemotePath(parentPath, name) {
|
||||||
|
if (!parentPath || parentPath === ".") return name;
|
||||||
|
if (parentPath.endsWith("/")) return `${parentPath}${name}`;
|
||||||
|
return `${parentPath}/${name}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeSftpEntry(entry, parentPath) {
|
||||||
|
const name = entry.name;
|
||||||
|
const type = entry.type === "d" ? "directory" : "file";
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
path: joinRemotePath(parentPath, name),
|
||||||
|
type,
|
||||||
|
size: type === "directory" ? null : typeof entry.size === "number" ? entry.size : null,
|
||||||
|
modified: toIsoDate(entry.modifyTime),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeFtpEntry(entry, parentPath) {
|
||||||
|
const type = entry.type === 2 ? "directory" : "file";
|
||||||
|
return {
|
||||||
|
name: entry.name,
|
||||||
|
path: joinRemotePath(parentPath, entry.name),
|
||||||
|
type,
|
||||||
|
size: type === "directory" ? null : typeof entry.size === "number" ? entry.size : null,
|
||||||
|
modified: toIsoDate(entry.modifiedAt ?? entry.rawModifiedAt),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function bufferFromWritable(writeFn) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
/** @type {Buffer[]} */
|
||||||
|
const chunks = [];
|
||||||
|
const writable = new Writable({
|
||||||
|
write(chunk, _encoding, callback) {
|
||||||
|
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
||||||
|
callback();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
writable.on("finish", () => resolve(Buffer.concat(chunks)));
|
||||||
|
writable.on("error", reject);
|
||||||
|
Promise.resolve(writeFn(writable)).catch(reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveWriteBody(ctx) {
|
||||||
|
if (ctx.config != null && typeof ctx.config === "object" && "body" in ctx.config) {
|
||||||
|
const body = ctx.config.body;
|
||||||
|
if (Buffer.isBuffer(body) || body instanceof Uint8Array) return Buffer.from(body);
|
||||||
|
if (typeof body === "string") return Buffer.from(body, "utf8");
|
||||||
|
return Buffer.from(JSON.stringify(body), "utf8");
|
||||||
|
}
|
||||||
|
if (ctx.data?.file != null) {
|
||||||
|
const file = ctx.data.file;
|
||||||
|
if (Buffer.isBuffer(file) || file instanceof Uint8Array) return Buffer.from(file);
|
||||||
|
}
|
||||||
|
if (ctx.data?.body != null) {
|
||||||
|
const body = ctx.data.body;
|
||||||
|
if (Buffer.isBuffer(body) || body instanceof Uint8Array) return Buffer.from(body);
|
||||||
|
if (typeof body === "string") return Buffer.from(body, "utf8");
|
||||||
|
return Buffer.from(JSON.stringify(body), "utf8");
|
||||||
|
}
|
||||||
|
throw new Error("remote-fs: write requires ctx.config.body, ctx.data.body, or ctx.data.file");
|
||||||
|
}
|
||||||
|
|
||||||
|
async function withSftp(ctx, protocol, fn) {
|
||||||
|
const auth = await resolveAuth(ctx);
|
||||||
|
const client = new SftpClient();
|
||||||
|
/** @type {Record<string, unknown>} */
|
||||||
|
const connectOptions = {
|
||||||
|
host: resolveHost(ctx),
|
||||||
|
port: resolvePort(ctx, protocol),
|
||||||
|
username: auth.username,
|
||||||
|
};
|
||||||
|
if (auth.privateKey) {
|
||||||
|
connectOptions.privateKey = auth.privateKey;
|
||||||
|
if (auth.passphrase) connectOptions.passphrase = auth.passphrase;
|
||||||
|
} else {
|
||||||
|
connectOptions.password = auth.password;
|
||||||
|
}
|
||||||
|
if (ctx.config?.readyTimeout != null) {
|
||||||
|
connectOptions.readyTimeout = Number(ctx.config.readyTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
await client.connect(connectOptions);
|
||||||
|
try {
|
||||||
|
return await fn(client);
|
||||||
|
} finally {
|
||||||
|
await client.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function withFtp(ctx, protocol, fn) {
|
||||||
|
const auth = await resolveAuth(ctx);
|
||||||
|
const client = new Client(
|
||||||
|
typeof ctx.config?.timeout === "number" ? ctx.config.timeout : 30000,
|
||||||
|
);
|
||||||
|
const secure = ctx.config?.secure === true || ctx.config?.secure === "implicit";
|
||||||
|
await client.access({
|
||||||
|
host: resolveHost(ctx),
|
||||||
|
port: resolvePort(ctx, protocol),
|
||||||
|
user: auth.username,
|
||||||
|
password: auth.password ?? "",
|
||||||
|
secure,
|
||||||
|
});
|
||||||
|
if (ctx.config?.passive === false) {
|
||||||
|
client.ftp.passive = false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return await fn(client);
|
||||||
|
} finally {
|
||||||
|
client.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function runAction(protocol, ctx, action) {
|
||||||
|
const path = resolvePath(ctx, { required: action !== "list", label: "path" });
|
||||||
|
|
||||||
|
if (protocol === "sftp") {
|
||||||
|
return withSftp(ctx, protocol, async (client) => {
|
||||||
|
switch (action) {
|
||||||
|
case "list": {
|
||||||
|
const listPath = resolvePath(ctx);
|
||||||
|
const items = await client.list(listPath);
|
||||||
|
const entries = items.map((item) => normalizeSftpEntry(item, listPath));
|
||||||
|
return { path: listPath, entries, count: entries.length };
|
||||||
|
}
|
||||||
|
case "read": {
|
||||||
|
const outputVar =
|
||||||
|
typeof ctx.config?.outputVar === "string" && ctx.config.outputVar.length > 0
|
||||||
|
? ctx.config.outputVar
|
||||||
|
: "file";
|
||||||
|
const file = await client.get(path);
|
||||||
|
const buffer = Buffer.isBuffer(file) ? file : Buffer.from(file);
|
||||||
|
const encoding = ctx.config?.encoding ?? ctx.data?.encoding;
|
||||||
|
/** @type {Record<string, unknown>} */
|
||||||
|
const out = {
|
||||||
|
path,
|
||||||
|
[outputVar]: buffer,
|
||||||
|
contentLength: buffer.length,
|
||||||
|
};
|
||||||
|
if (encoding === "utf8" || encoding === "text") out.text = buffer.toString("utf8");
|
||||||
|
if (encoding === "base64") out.base64 = buffer.toString("base64");
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
case "write": {
|
||||||
|
const body = resolveWriteBody(ctx);
|
||||||
|
await client.put(body, path);
|
||||||
|
return { path, written: true, contentLength: body.length };
|
||||||
|
}
|
||||||
|
case "delete": {
|
||||||
|
await client.delete(path);
|
||||||
|
return { path, deleted: true };
|
||||||
|
}
|
||||||
|
case "stat": {
|
||||||
|
const stat = await client.stat(path);
|
||||||
|
return {
|
||||||
|
path,
|
||||||
|
type: stat.isDirectory ? "directory" : "file",
|
||||||
|
size: typeof stat.size === "number" ? stat.size : null,
|
||||||
|
modified: toIsoDate(stat.modifyTime),
|
||||||
|
accessed: toIsoDate(stat.accessTime),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
case "mkdir": {
|
||||||
|
const recursive = ctx.config?.recursive !== false;
|
||||||
|
await client.mkdir(path, recursive);
|
||||||
|
return { path, created: true, recursive };
|
||||||
|
}
|
||||||
|
case "rename": {
|
||||||
|
const destination = ctx.config?.destination ?? ctx.data?.destination;
|
||||||
|
if (typeof destination !== "string" || destination.length === 0) {
|
||||||
|
throw new Error("remote-fs: rename requires destination");
|
||||||
|
}
|
||||||
|
await client.rename(path, destination);
|
||||||
|
return { path, destination, renamed: true };
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new Error(`remote-fs: unsupported action "${action}"`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return withFtp(ctx, protocol, async (client) => {
|
||||||
|
switch (action) {
|
||||||
|
case "list": {
|
||||||
|
const listPath = resolvePath(ctx);
|
||||||
|
const items = await client.list(listPath === "." ? undefined : listPath);
|
||||||
|
const entries = items.map((item) => normalizeFtpEntry(item, listPath));
|
||||||
|
return { path: listPath, entries, count: entries.length };
|
||||||
|
}
|
||||||
|
case "read": {
|
||||||
|
const outputVar =
|
||||||
|
typeof ctx.config?.outputVar === "string" && ctx.config.outputVar.length > 0
|
||||||
|
? ctx.config.outputVar
|
||||||
|
: "file";
|
||||||
|
const buffer = await bufferFromWritable((writable) => client.downloadTo(writable, path));
|
||||||
|
const encoding = ctx.config?.encoding ?? ctx.data?.encoding;
|
||||||
|
/** @type {Record<string, unknown>} */
|
||||||
|
const out = {
|
||||||
|
path,
|
||||||
|
[outputVar]: buffer,
|
||||||
|
contentLength: buffer.length,
|
||||||
|
};
|
||||||
|
if (encoding === "utf8" || encoding === "text") out.text = buffer.toString("utf8");
|
||||||
|
if (encoding === "base64") out.base64 = buffer.toString("base64");
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
case "write": {
|
||||||
|
const body = resolveWriteBody(ctx);
|
||||||
|
const stream = Readable.from(body);
|
||||||
|
await client.uploadFrom(stream, path);
|
||||||
|
return { path, written: true, contentLength: body.length };
|
||||||
|
}
|
||||||
|
case "delete": {
|
||||||
|
await client.remove(path);
|
||||||
|
return { path, deleted: true };
|
||||||
|
}
|
||||||
|
case "stat": {
|
||||||
|
const size = await client.size(path);
|
||||||
|
const modified = await client.lastMod(path);
|
||||||
|
return {
|
||||||
|
path,
|
||||||
|
type: "file",
|
||||||
|
size: typeof size === "number" ? size : null,
|
||||||
|
modified: toIsoDate(modified),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
case "mkdir": {
|
||||||
|
await client.ensureDir(path);
|
||||||
|
return { path, created: true, recursive: true };
|
||||||
|
}
|
||||||
|
case "rename": {
|
||||||
|
const destination = ctx.config?.destination ?? ctx.data?.destination;
|
||||||
|
if (typeof destination !== "string" || destination.length === 0) {
|
||||||
|
throw new Error("remote-fs: rename requires destination");
|
||||||
|
}
|
||||||
|
await client.rename(path, destination);
|
||||||
|
return { path, destination, renamed: true };
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new Error(`remote-fs: unsupported action "${action}"`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function remoteFs(ctx) {
|
||||||
|
const protocol = resolveProtocol(ctx);
|
||||||
|
const action = resolveAction(ctx);
|
||||||
|
const host = resolveHost(ctx);
|
||||||
|
const port = resolvePort(ctx, protocol);
|
||||||
|
|
||||||
|
log.info({ protocol, action, host, port }, "remote-fs: starting");
|
||||||
|
|
||||||
|
const result = await runAction(protocol, ctx, action);
|
||||||
|
const output = {
|
||||||
|
protocol,
|
||||||
|
action,
|
||||||
|
host,
|
||||||
|
...result,
|
||||||
|
};
|
||||||
|
|
||||||
|
log.info(
|
||||||
|
{ protocol, action, path: output.path ?? null, count: output.count ?? null },
|
||||||
|
"remote-fs: complete",
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
output: { ...mergeData(ctx.data), ...output },
|
||||||
|
context: { ...passContext(ctx), ...output },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
remoteFs.meta = {
|
||||||
|
description: "Access remote files over SFTP or FTP/FTPS",
|
||||||
|
previewConfigKey: "protocol",
|
||||||
|
tags: ["SFTP", "FTP", "storage"],
|
||||||
|
config: {
|
||||||
|
protocol: {
|
||||||
|
type: "string",
|
||||||
|
default: "sftp",
|
||||||
|
enum: ["sftp", "ftp"],
|
||||||
|
description: "Transfer protocol",
|
||||||
|
},
|
||||||
|
action: {
|
||||||
|
type: "string",
|
||||||
|
default: "list",
|
||||||
|
enum: ["list", "read", "write", "delete", "stat", "mkdir", "rename"],
|
||||||
|
description: "Operation to perform",
|
||||||
|
},
|
||||||
|
host: { type: "string", required: true, description: "Server hostname" },
|
||||||
|
port: { type: "number", required: false, description: "Port (default 22 for SFTP, 21 for FTP)" },
|
||||||
|
path: {
|
||||||
|
type: "string",
|
||||||
|
required: false,
|
||||||
|
description: "Remote directory for list, or file path for other actions",
|
||||||
|
},
|
||||||
|
username: { type: "string", required: false, description: "Login username" },
|
||||||
|
usernameSecret: { type: "string", required: false, description: "Named secret for username" },
|
||||||
|
password: { type: "string", required: false, description: "Login password" },
|
||||||
|
passwordSecret: { type: "string", required: false, description: "Named secret for password" },
|
||||||
|
privateKeySecret: {
|
||||||
|
type: "string",
|
||||||
|
required: false,
|
||||||
|
description: "Named secret holding an SFTP private key (PEM)",
|
||||||
|
},
|
||||||
|
privateKey: { type: "string", required: false, description: "Inline SFTP private key (PEM)" },
|
||||||
|
passphraseSecret: {
|
||||||
|
type: "string",
|
||||||
|
required: false,
|
||||||
|
description: "Named secret for encrypted private key passphrase",
|
||||||
|
},
|
||||||
|
passphrase: { type: "string", required: false, description: "Private key passphrase" },
|
||||||
|
secure: {
|
||||||
|
type: "boolean",
|
||||||
|
default: false,
|
||||||
|
description: "Use FTPS for FTP protocol",
|
||||||
|
},
|
||||||
|
passive: {
|
||||||
|
type: "boolean",
|
||||||
|
default: true,
|
||||||
|
description: "Use passive FTP mode",
|
||||||
|
},
|
||||||
|
recursive: {
|
||||||
|
type: "boolean",
|
||||||
|
default: true,
|
||||||
|
description: "Create parent directories for mkdir",
|
||||||
|
},
|
||||||
|
destination: {
|
||||||
|
type: "string",
|
||||||
|
required: false,
|
||||||
|
description: "Destination path for rename",
|
||||||
|
},
|
||||||
|
body: { type: "any", required: false, description: "Write payload" },
|
||||||
|
outputVar: {
|
||||||
|
type: "string",
|
||||||
|
default: "file",
|
||||||
|
description: "Output key for read action bytes",
|
||||||
|
},
|
||||||
|
encoding: {
|
||||||
|
type: "string",
|
||||||
|
required: false,
|
||||||
|
enum: ["utf8", "text", "base64"],
|
||||||
|
description: "Optional read decoding helper",
|
||||||
|
},
|
||||||
|
timeout: { type: "number", required: false, description: "FTP client timeout in ms" },
|
||||||
|
readyTimeout: { type: "number", required: false, description: "SFTP ready timeout in ms" },
|
||||||
|
},
|
||||||
|
input: {
|
||||||
|
protocol: { type: "string", required: false },
|
||||||
|
action: { type: "string", required: false },
|
||||||
|
host: { type: "string", required: false },
|
||||||
|
path: { type: "string", required: false },
|
||||||
|
username: { type: "string", required: false },
|
||||||
|
password: { type: "string", required: false },
|
||||||
|
body: { type: "any", required: false },
|
||||||
|
file: { type: "buffer", required: false },
|
||||||
|
destination: { type: "string", required: false },
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
protocol: { type: "string" },
|
||||||
|
action: { type: "string" },
|
||||||
|
host: { type: "string" },
|
||||||
|
entries: { type: "array", required: false, description: "list results" },
|
||||||
|
file: { type: "buffer", required: false, description: "read bytes (or outputVar)" },
|
||||||
|
written: { type: "boolean", required: false },
|
||||||
|
deleted: { type: "boolean", required: false },
|
||||||
|
renamed: { type: "boolean", required: false },
|
||||||
|
created: { type: "boolean", required: false },
|
||||||
|
},
|
||||||
|
context: {
|
||||||
|
protocol: { type: "string" },
|
||||||
|
action: { type: "string" },
|
||||||
|
host: { type: "string" },
|
||||||
|
},
|
||||||
|
example: {
|
||||||
|
data: {},
|
||||||
|
config: {
|
||||||
|
protocol: "sftp",
|
||||||
|
action: "list",
|
||||||
|
host: "sftp.example.com",
|
||||||
|
path: "/incoming",
|
||||||
|
username: "deploy",
|
||||||
|
passwordSecret: "sftp_password",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default remoteFs;
|
||||||
Generated
+118
@@ -35,6 +35,9 @@ importers:
|
|||||||
axios:
|
axios:
|
||||||
specifier: ^1.19.0
|
specifier: ^1.19.0
|
||||||
version: 1.19.0
|
version: 1.19.0
|
||||||
|
basic-ftp:
|
||||||
|
specifier: ^6.2.0
|
||||||
|
version: 6.2.0
|
||||||
bcryptjs:
|
bcryptjs:
|
||||||
specifier: ^3.0.2
|
specifier: ^3.0.2
|
||||||
version: 3.0.3
|
version: 3.0.3
|
||||||
@@ -68,6 +71,9 @@ importers:
|
|||||||
pino-roll:
|
pino-roll:
|
||||||
specifier: ^4.0.0
|
specifier: ^4.0.0
|
||||||
version: 4.0.0
|
version: 4.0.0
|
||||||
|
ssh2-sftp-client:
|
||||||
|
specifier: ^12.1.1
|
||||||
|
version: 12.1.1
|
||||||
webdav:
|
webdav:
|
||||||
specifier: ^5.10.0
|
specifier: ^5.10.0
|
||||||
version: 5.10.0
|
version: 5.10.0
|
||||||
@@ -985,6 +991,9 @@ packages:
|
|||||||
asn1.js@5.4.1:
|
asn1.js@5.4.1:
|
||||||
resolution: {integrity: sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==}
|
resolution: {integrity: sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==}
|
||||||
|
|
||||||
|
asn1@0.2.6:
|
||||||
|
resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==}
|
||||||
|
|
||||||
asynckit@0.4.0:
|
asynckit@0.4.0:
|
||||||
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
|
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
|
||||||
|
|
||||||
@@ -1013,6 +1022,13 @@ packages:
|
|||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
basic-ftp@6.2.0:
|
||||||
|
resolution: {integrity: sha512-H8eLjhoYPbOI717FLP8fGE7XInkMI7Ucj/ft0fp1avABtSiV5Bb2kYzScnOqlvJZs/KJZypr9Mp5zJmhaPFAEg==}
|
||||||
|
engines: {node: '>=10.0.0'}
|
||||||
|
|
||||||
|
bcrypt-pbkdf@1.0.2:
|
||||||
|
resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==}
|
||||||
|
|
||||||
bcryptjs@3.0.3:
|
bcryptjs@3.0.3:
|
||||||
resolution: {integrity: sha512-GlF5wPWnSa/X5LKM1o0wz0suXIINz1iHRLvTS+sLyi7XPbe5ycmYI3DlZqVGZZtDgl4DmasFg7gOB3JYbphV5g==}
|
resolution: {integrity: sha512-GlF5wPWnSa/X5LKM1o0wz0suXIINz1iHRLvTS+sLyi7XPbe5ycmYI3DlZqVGZZtDgl4DmasFg7gOB3JYbphV5g==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@@ -1042,6 +1058,13 @@ packages:
|
|||||||
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
|
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
buffer-from@1.1.2:
|
||||||
|
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
|
||||||
|
|
||||||
|
buildcheck@0.0.7:
|
||||||
|
resolution: {integrity: sha512-lHblz4ahamxpTmnsk+MNTRWsjYKv965MwOrSJyeD588rR3Jcu7swE+0wN5F+PbL5cjgu/9ObkhfzEPuofEMwLA==}
|
||||||
|
engines: {node: '>=10.0.0'}
|
||||||
|
|
||||||
byte-length@1.0.2:
|
byte-length@1.0.2:
|
||||||
resolution: {integrity: sha512-ovBpjmsgd/teRmgcPh23d4gJvxDoXtAzEL9xTfMU8Yc2kqCDb7L9jAG0XHl1nzuGl+h3ebCIF1i62UFyA9V/2Q==}
|
resolution: {integrity: sha512-ovBpjmsgd/teRmgcPh23d4gJvxDoXtAzEL9xTfMU8Yc2kqCDb7L9jAG0XHl1nzuGl+h3ebCIF1i62UFyA9V/2Q==}
|
||||||
|
|
||||||
@@ -1074,6 +1097,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==}
|
resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==}
|
||||||
engines: {node: '>= 12'}
|
engines: {node: '>= 12'}
|
||||||
|
|
||||||
|
concat-stream@2.0.0:
|
||||||
|
resolution: {integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==}
|
||||||
|
engines: {'0': node >= 6.0}
|
||||||
|
|
||||||
content-disposition@0.5.4:
|
content-disposition@0.5.4:
|
||||||
resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
|
resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
@@ -1095,6 +1122,10 @@ packages:
|
|||||||
cose-base@2.2.0:
|
cose-base@2.2.0:
|
||||||
resolution: {integrity: sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==}
|
resolution: {integrity: sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==}
|
||||||
|
|
||||||
|
cpu-features@0.0.10:
|
||||||
|
resolution: {integrity: sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA==}
|
||||||
|
engines: {node: '>=10.0.0'}
|
||||||
|
|
||||||
cronstrue@3.24.0:
|
cronstrue@3.24.0:
|
||||||
resolution: {integrity: sha512-t/Ji3Ur2c/pzhIAWNwC0ftl3JAE4dLfCjAdZoTZXmPDZwcispnS1PaMcMS4OmIIXyIVouAz+yw+mfQiE3hz5OQ==}
|
resolution: {integrity: sha512-t/Ji3Ur2c/pzhIAWNwC0ftl3JAE4dLfCjAdZoTZXmPDZwcispnS1PaMcMS4OmIIXyIVouAz+yw+mfQiE3hz5OQ==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@@ -1829,6 +1860,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==}
|
resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
nan@2.28.0:
|
||||||
|
resolution: {integrity: sha512-fTsDz99OTq2sVePhGdp4qQhggZFtKr64ZNVyVajRKtMOkJxYekplBh577PiJB12v/D3s2E5cGtOI45LWp6rnLQ==}
|
||||||
|
|
||||||
nanoid@3.3.18:
|
nanoid@3.3.18:
|
||||||
resolution: {integrity: sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==}
|
resolution: {integrity: sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==}
|
||||||
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||||
@@ -1986,6 +2020,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==}
|
resolution: {integrity: sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
readable-stream@3.6.2:
|
||||||
|
resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
|
||||||
|
engines: {node: '>= 6'}
|
||||||
|
|
||||||
real-require@0.2.0:
|
real-require@0.2.0:
|
||||||
resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==}
|
resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==}
|
||||||
engines: {node: '>= 12.13.0'}
|
engines: {node: '>= 12.13.0'}
|
||||||
@@ -2103,6 +2141,14 @@ packages:
|
|||||||
resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
|
resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
|
||||||
engines: {node: '>= 10.x'}
|
engines: {node: '>= 10.x'}
|
||||||
|
|
||||||
|
ssh2-sftp-client@12.1.1:
|
||||||
|
resolution: {integrity: sha512-wYVDgwkpcKG2iPGQQ+QR33xkWqLFIaVrYvA+uON4pmxTPaPuB81f1aooUEPN75e/9DCK6rrKYXb6zR6zP3+EtA==}
|
||||||
|
engines: {node: '>=18.20.4'}
|
||||||
|
|
||||||
|
ssh2@1.17.0:
|
||||||
|
resolution: {integrity: sha512-wPldCk3asibAjQ/kziWQQt1Wh3PgDFpC0XpwclzKcdT1vql6KeYxf5LIt4nlFkUeR8WuphYMKqUA56X4rjbfgQ==}
|
||||||
|
engines: {node: '>=10.16.0'}
|
||||||
|
|
||||||
state-local@1.0.7:
|
state-local@1.0.7:
|
||||||
resolution: {integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==}
|
resolution: {integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==}
|
||||||
|
|
||||||
@@ -2113,6 +2159,9 @@ packages:
|
|||||||
steed@1.1.3:
|
steed@1.1.3:
|
||||||
resolution: {integrity: sha512-EUkci0FAUiE4IvGTSKcDJIQ/eRUP2JJb56+fvZ4sdnguLTqIdKjSxUe138poW8mkvKWXW2sFPrgTsxqoISnmoA==}
|
resolution: {integrity: sha512-EUkci0FAUiE4IvGTSKcDJIQ/eRUP2JJb56+fvZ4sdnguLTqIdKjSxUe138poW8mkvKWXW2sFPrgTsxqoISnmoA==}
|
||||||
|
|
||||||
|
string_decoder@1.3.0:
|
||||||
|
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
|
||||||
|
|
||||||
strnum@2.4.2:
|
strnum@2.4.2:
|
||||||
resolution: {integrity: sha512-rDG3Ah4TV0k1hWvLSzkZtMmLN9+eS+h3knq4MP6A42Y3Yh5qGNnOUs1jJkoSr8FG5dsL28c7KgkIBzSEykqtuw==}
|
resolution: {integrity: sha512-rDG3Ah4TV0k1hWvLSzkZtMmLN9+eS+h3knq4MP6A42Y3Yh5qGNnOUs1jJkoSr8FG5dsL28c7KgkIBzSEykqtuw==}
|
||||||
|
|
||||||
@@ -2165,6 +2214,12 @@ packages:
|
|||||||
tslib@2.8.1:
|
tslib@2.8.1:
|
||||||
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
||||||
|
|
||||||
|
tweetnacl@0.14.5:
|
||||||
|
resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==}
|
||||||
|
|
||||||
|
typedarray@0.0.6:
|
||||||
|
resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==}
|
||||||
|
|
||||||
update-browserslist-db@1.3.1:
|
update-browserslist-db@1.3.1:
|
||||||
resolution: {integrity: sha512-ZZ61DsRsOnakl74HAmp3oSN4aXUmEWXf+i/yv0h7tIBfICc3VdrFErQKUUKPgu3AMsTUMbcongALEN4l6GSUrQ==}
|
resolution: {integrity: sha512-ZZ61DsRsOnakl74HAmp3oSN4aXUmEWXf+i/yv0h7tIBfICc3VdrFErQKUUKPgu3AMsTUMbcongALEN4l6GSUrQ==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@@ -2178,6 +2233,9 @@ packages:
|
|||||||
url-parse@1.5.10:
|
url-parse@1.5.10:
|
||||||
resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}
|
resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}
|
||||||
|
|
||||||
|
util-deprecate@1.0.2:
|
||||||
|
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||||
|
|
||||||
uuid@14.0.1:
|
uuid@14.0.1:
|
||||||
resolution: {integrity: sha512-6ZxzVpzDXDa3bJWaHilVayA+BH/1zmxCJoVgvmqJnid/gPoKHxUrS/aC/T6LGQtNHT+XHG9fXPJB4d+IrU30Ew==}
|
resolution: {integrity: sha512-6ZxzVpzDXDa3bJWaHilVayA+BH/1zmxCJoVgvmqJnid/gPoKHxUrS/aC/T6LGQtNHT+XHG9fXPJB4d+IrU30Ew==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@@ -3159,6 +3217,10 @@ snapshots:
|
|||||||
minimalistic-assert: 1.0.1
|
minimalistic-assert: 1.0.1
|
||||||
safer-buffer: 2.1.2
|
safer-buffer: 2.1.2
|
||||||
|
|
||||||
|
asn1@0.2.6:
|
||||||
|
dependencies:
|
||||||
|
safer-buffer: 2.1.2
|
||||||
|
|
||||||
asynckit@0.4.0: {}
|
asynckit@0.4.0: {}
|
||||||
|
|
||||||
atomic-sleep@1.0.0: {}
|
atomic-sleep@1.0.0: {}
|
||||||
@@ -3186,6 +3248,12 @@ snapshots:
|
|||||||
|
|
||||||
baseline-browser-mapping@2.11.14: {}
|
baseline-browser-mapping@2.11.14: {}
|
||||||
|
|
||||||
|
basic-ftp@6.2.0: {}
|
||||||
|
|
||||||
|
bcrypt-pbkdf@1.0.2:
|
||||||
|
dependencies:
|
||||||
|
tweetnacl: 0.14.5
|
||||||
|
|
||||||
bcryptjs@3.0.3: {}
|
bcryptjs@3.0.3: {}
|
||||||
|
|
||||||
better-sqlite3@13.0.3:
|
better-sqlite3@13.0.3:
|
||||||
@@ -3214,6 +3282,11 @@ snapshots:
|
|||||||
node-releases: 2.0.53
|
node-releases: 2.0.53
|
||||||
update-browserslist-db: 1.3.1(browserslist@4.28.8)
|
update-browserslist-db: 1.3.1(browserslist@4.28.8)
|
||||||
|
|
||||||
|
buffer-from@1.1.2: {}
|
||||||
|
|
||||||
|
buildcheck@0.0.7:
|
||||||
|
optional: true
|
||||||
|
|
||||||
byte-length@1.0.2: {}
|
byte-length@1.0.2: {}
|
||||||
|
|
||||||
call-bind-apply-helpers@1.0.2:
|
call-bind-apply-helpers@1.0.2:
|
||||||
@@ -3237,6 +3310,13 @@ snapshots:
|
|||||||
|
|
||||||
commander@8.3.0: {}
|
commander@8.3.0: {}
|
||||||
|
|
||||||
|
concat-stream@2.0.0:
|
||||||
|
dependencies:
|
||||||
|
buffer-from: 1.1.2
|
||||||
|
inherits: 2.0.4
|
||||||
|
readable-stream: 3.6.2
|
||||||
|
typedarray: 0.0.6
|
||||||
|
|
||||||
content-disposition@0.5.4:
|
content-disposition@0.5.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
safe-buffer: 5.2.1
|
safe-buffer: 5.2.1
|
||||||
@@ -3255,6 +3335,12 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
layout-base: 2.0.1
|
layout-base: 2.0.1
|
||||||
|
|
||||||
|
cpu-features@0.0.10:
|
||||||
|
dependencies:
|
||||||
|
buildcheck: 0.0.7
|
||||||
|
nan: 2.28.0
|
||||||
|
optional: true
|
||||||
|
|
||||||
cronstrue@3.24.0: {}
|
cronstrue@3.24.0: {}
|
||||||
|
|
||||||
cross-spawn@7.0.6:
|
cross-spawn@7.0.6:
|
||||||
@@ -3996,6 +4082,9 @@ snapshots:
|
|||||||
|
|
||||||
mustache@4.2.0: {}
|
mustache@4.2.0: {}
|
||||||
|
|
||||||
|
nan@2.28.0:
|
||||||
|
optional: true
|
||||||
|
|
||||||
nanoid@3.3.18: {}
|
nanoid@3.3.18: {}
|
||||||
|
|
||||||
nested-property@4.0.0: {}
|
nested-property@4.0.0: {}
|
||||||
@@ -4129,6 +4218,12 @@ snapshots:
|
|||||||
|
|
||||||
react@19.2.8: {}
|
react@19.2.8: {}
|
||||||
|
|
||||||
|
readable-stream@3.6.2:
|
||||||
|
dependencies:
|
||||||
|
inherits: 2.0.4
|
||||||
|
string_decoder: 1.3.0
|
||||||
|
util-deprecate: 1.0.2
|
||||||
|
|
||||||
real-require@0.2.0: {}
|
real-require@0.2.0: {}
|
||||||
|
|
||||||
real-require@1.0.0: {}
|
real-require@1.0.0: {}
|
||||||
@@ -4244,6 +4339,19 @@ snapshots:
|
|||||||
|
|
||||||
split2@4.2.0: {}
|
split2@4.2.0: {}
|
||||||
|
|
||||||
|
ssh2-sftp-client@12.1.1:
|
||||||
|
dependencies:
|
||||||
|
concat-stream: 2.0.0
|
||||||
|
ssh2: 1.17.0
|
||||||
|
|
||||||
|
ssh2@1.17.0:
|
||||||
|
dependencies:
|
||||||
|
asn1: 0.2.6
|
||||||
|
bcrypt-pbkdf: 1.0.2
|
||||||
|
optionalDependencies:
|
||||||
|
cpu-features: 0.0.10
|
||||||
|
nan: 2.28.0
|
||||||
|
|
||||||
state-local@1.0.7: {}
|
state-local@1.0.7: {}
|
||||||
|
|
||||||
statuses@2.0.2: {}
|
statuses@2.0.2: {}
|
||||||
@@ -4256,6 +4364,10 @@ snapshots:
|
|||||||
fastseries: 1.7.2
|
fastseries: 1.7.2
|
||||||
reusify: 1.1.0
|
reusify: 1.1.0
|
||||||
|
|
||||||
|
string_decoder@1.3.0:
|
||||||
|
dependencies:
|
||||||
|
safe-buffer: 5.2.1
|
||||||
|
|
||||||
strnum@2.4.2:
|
strnum@2.4.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
anynum: 1.0.1
|
anynum: 1.0.1
|
||||||
@@ -4291,6 +4403,10 @@ snapshots:
|
|||||||
|
|
||||||
tslib@2.8.1: {}
|
tslib@2.8.1: {}
|
||||||
|
|
||||||
|
tweetnacl@0.14.5: {}
|
||||||
|
|
||||||
|
typedarray@0.0.6: {}
|
||||||
|
|
||||||
update-browserslist-db@1.3.1(browserslist@4.28.8):
|
update-browserslist-db@1.3.1(browserslist@4.28.8):
|
||||||
dependencies:
|
dependencies:
|
||||||
browserslist: 4.28.8
|
browserslist: 4.28.8
|
||||||
@@ -4304,6 +4420,8 @@ snapshots:
|
|||||||
querystringify: 2.2.0
|
querystringify: 2.2.0
|
||||||
requires-port: 1.0.0
|
requires-port: 1.0.0
|
||||||
|
|
||||||
|
util-deprecate@1.0.2: {}
|
||||||
|
|
||||||
uuid@14.0.1: {}
|
uuid@14.0.1: {}
|
||||||
|
|
||||||
vite@7.3.6(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0):
|
vite@7.3.6(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0):
|
||||||
|
|||||||
Reference in New Issue
Block a user