feat(13-01): add 18 backends to BACKEND_REGISTRY with category field
- Removed explicit BackendType union literal; derived via keyof typeof BACKEND_REGISTRY - Added BackendCategory type and category field to all 18 backend entries - Added BackendMeta interface for individual entry typing - Removed circular Record<BackendType,...> cast; replaced with as const - Added 11 new backends: azure-files, swift, gdrive, dropbox, box, pcloud, ftp, webdav, smb, http, seafile - Updated registry.test.ts: 48 tests covering all 18 backends, category assertions, field validation
This commit is contained in:
+463
-89
@@ -3,8 +3,11 @@
|
||||
// IMPORTANT: FieldDef.key values MUST match rclone config key names exactly.
|
||||
// These keys are used by Phase 2 generators to build rclone.conf INI content.
|
||||
// Verify against https://rclone.org/azureblob/ and https://rclone.org/s3/ before Phase 2.
|
||||
//
|
||||
// BackendType is DERIVED from keyof typeof BACKEND_REGISTRY — do NOT add a manual union.
|
||||
// BackendCategory is the grouping used for UI categorization and search.
|
||||
|
||||
export type BackendType = 'azureblob' | 's3' | 's3-compatible' | 'onedrive' | 'sftp' | 'gcs' | 'b2';
|
||||
export type BackendCategory = 'cloud-object-storage' | 'cloud-drives' | 'protocol-based';
|
||||
|
||||
export interface FieldDef {
|
||||
key: string; // MUST match rclone config key exactly (snake_case)
|
||||
@@ -18,15 +21,23 @@ export interface FieldDef {
|
||||
tooltipText?: string;
|
||||
}
|
||||
|
||||
export interface BackendMeta {
|
||||
displayName: string;
|
||||
description: string;
|
||||
category: BackendCategory;
|
||||
fields: FieldDef[];
|
||||
}
|
||||
|
||||
export const BACKEND_REGISTRY = {
|
||||
azureblob: {
|
||||
displayName: 'Azure Blob Storage',
|
||||
description: 'Microsoft Azure cloud storage',
|
||||
category: 'cloud-object-storage' as const,
|
||||
fields: [
|
||||
{
|
||||
key: 'account',
|
||||
label: 'Storage Account Name',
|
||||
inputType: 'text',
|
||||
inputType: 'text' as const,
|
||||
required: true,
|
||||
placeholder: 'mystorageaccount',
|
||||
helpText: 'The storage account name (not the full URL)',
|
||||
@@ -38,7 +49,7 @@ export const BACKEND_REGISTRY = {
|
||||
{
|
||||
key: 'key',
|
||||
label: 'Access Key',
|
||||
inputType: 'password',
|
||||
inputType: 'password' as const,
|
||||
required: false,
|
||||
helpText: 'Base64-encoded storage account key. Provide either this or a SAS URL, not both.',
|
||||
tooltipText: 'The full storage account key grants unrestricted read/write access to all containers in the account. Keep this secret. If you only need limited access, use a SAS URL instead.',
|
||||
@@ -46,7 +57,7 @@ export const BACKEND_REGISTRY = {
|
||||
{
|
||||
key: 'sas_url',
|
||||
label: 'SAS URL',
|
||||
inputType: 'password',
|
||||
inputType: 'password' as const,
|
||||
required: false,
|
||||
placeholder: 'https://mystorageaccount.blob.core.windows.net/?sv=...',
|
||||
helpText: 'Full SAS URL including account and container. Provide either this or an access key, not both.',
|
||||
@@ -57,18 +68,19 @@ export const BACKEND_REGISTRY = {
|
||||
s3: {
|
||||
displayName: 'Amazon S3',
|
||||
description: 'AWS Simple Storage Service',
|
||||
category: 'cloud-object-storage' as const,
|
||||
fields: [
|
||||
{
|
||||
key: 'provider',
|
||||
label: 'Provider',
|
||||
inputType: 'select',
|
||||
inputType: 'select' as const,
|
||||
required: true,
|
||||
options: [{ value: 'AWS', label: 'Amazon S3' }],
|
||||
},
|
||||
{
|
||||
key: 'access_key_id',
|
||||
label: 'Access Key ID',
|
||||
inputType: 'text',
|
||||
inputType: 'text' as const,
|
||||
required: true,
|
||||
placeholder: 'AKIAIOSFODNN7EXAMPLE',
|
||||
helpText: 'The access key ID from your IAM credentials (starts with AKIA for long-term keys).',
|
||||
@@ -77,7 +89,7 @@ export const BACKEND_REGISTRY = {
|
||||
{
|
||||
key: 'secret_access_key',
|
||||
label: 'Secret Access Key',
|
||||
inputType: 'password',
|
||||
inputType: 'password' as const,
|
||||
required: true,
|
||||
helpText: 'The secret access key paired with your Access Key ID. Only shown once at creation time.',
|
||||
tooltipText: 'This value is shown only once when you create an access key in IAM. If you did not save it, delete the existing key and create a new one. Never share or commit this value — treat it as a password.',
|
||||
@@ -85,7 +97,7 @@ export const BACKEND_REGISTRY = {
|
||||
{
|
||||
key: 'region',
|
||||
label: 'Region',
|
||||
inputType: 'text',
|
||||
inputType: 'text' as const,
|
||||
required: true,
|
||||
placeholder: 'us-east-1',
|
||||
tooltipText: 'The AWS region where your S3 bucket is located. Find this in the S3 console next to your bucket name (e.g. us-east-1, eu-west-2, ap-southeast-1).',
|
||||
@@ -99,11 +111,12 @@ export const BACKEND_REGISTRY = {
|
||||
's3-compatible': {
|
||||
displayName: 'S3-Compatible',
|
||||
description: 'Wasabi, MinIO, Cloudflare R2, and others',
|
||||
category: 'cloud-object-storage' as const,
|
||||
fields: [
|
||||
{
|
||||
key: 'provider',
|
||||
label: 'Provider',
|
||||
inputType: 'select',
|
||||
inputType: 'select' as const,
|
||||
required: true,
|
||||
options: [{ value: 'Other', label: 'S3-Compatible' }],
|
||||
helpText: 'Covers Wasabi, MinIO, Cloudflare R2, and any S3-compatible storage',
|
||||
@@ -111,7 +124,7 @@ export const BACKEND_REGISTRY = {
|
||||
{
|
||||
key: 'access_key_id',
|
||||
label: 'Access Key ID',
|
||||
inputType: 'text',
|
||||
inputType: 'text' as const,
|
||||
required: true,
|
||||
helpText: 'The access key ID from your storage provider\'s dashboard.',
|
||||
tooltipText: 'Where to find this varies by provider: Wasabi — Account > Access Keys; Cloudflare R2 — R2 > Manage R2 API Tokens; MinIO — admin console > Identity > Users or Service Accounts.',
|
||||
@@ -119,7 +132,7 @@ export const BACKEND_REGISTRY = {
|
||||
{
|
||||
key: 'secret_access_key',
|
||||
label: 'Secret Access Key',
|
||||
inputType: 'password',
|
||||
inputType: 'password' as const,
|
||||
required: true,
|
||||
helpText: 'The secret key paired with your Access Key ID.',
|
||||
tooltipText: 'This value is typically shown only once when you create the key. Store it securely — if lost, you will need to generate a new key pair.',
|
||||
@@ -127,7 +140,7 @@ export const BACKEND_REGISTRY = {
|
||||
{
|
||||
key: 'endpoint',
|
||||
label: 'Endpoint URL',
|
||||
inputType: 'text',
|
||||
inputType: 'text' as const,
|
||||
required: true,
|
||||
placeholder: 'https://s3.wasabisys.com',
|
||||
helpText: 'The S3-compatible endpoint URL for your storage provider',
|
||||
@@ -136,57 +149,22 @@ export const BACKEND_REGISTRY = {
|
||||
{
|
||||
key: 'region',
|
||||
label: 'Region',
|
||||
inputType: 'text',
|
||||
inputType: 'text' as const,
|
||||
required: false,
|
||||
placeholder: 'us-east-1',
|
||||
helpText: 'Optional for most S3-compatible providers',
|
||||
},
|
||||
],
|
||||
},
|
||||
onedrive: {
|
||||
displayName: 'OneDrive',
|
||||
description: 'Microsoft OneDrive (paste pre-obtained rclone token)',
|
||||
fields: [
|
||||
{
|
||||
key: 'token',
|
||||
label: 'OAuth Token (JSON)',
|
||||
inputType: 'password',
|
||||
required: true,
|
||||
placeholder: '{"access_token":"...","token_type":"Bearer","refresh_token":"...","expiry":"..."}',
|
||||
helpText: 'Paste the JSON token from: rclone authorize "onedrive"',
|
||||
tooltipText: 'This is the JSON token obtained by running `rclone authorize "onedrive"` on a machine with a browser. The command opens a browser window, you authenticate, and rclone prints a JSON token — paste that entire JSON blob here.',
|
||||
},
|
||||
{
|
||||
key: 'drive_id',
|
||||
label: 'Drive ID',
|
||||
inputType: 'text',
|
||||
required: true,
|
||||
placeholder: 'b!...',
|
||||
helpText: 'The drive ID from your OneDrive. Found in the rclone authorize output.',
|
||||
tooltipText: 'The drive ID appears in the JSON output of `rclone authorize "onedrive"` — look for the "drive_id" field in the response. It typically starts with "b!" for business/SharePoint drives. Personal OneDrive drive IDs look like a UUID.',
|
||||
},
|
||||
{
|
||||
key: 'drive_type',
|
||||
label: 'Drive Type',
|
||||
inputType: 'select',
|
||||
required: true,
|
||||
options: [
|
||||
{ value: 'personal', label: 'Personal' },
|
||||
{ value: 'business', label: 'Business' },
|
||||
{ value: 'documentLibrary', label: 'SharePoint Document Library' },
|
||||
],
|
||||
helpText: 'Personal for consumer OneDrive, Business for Microsoft 365',
|
||||
},
|
||||
],
|
||||
},
|
||||
gcs: {
|
||||
displayName: 'Google Cloud Storage',
|
||||
description: 'Google Cloud Storage',
|
||||
category: 'cloud-object-storage' as const,
|
||||
fields: [
|
||||
{
|
||||
key: 'project_number',
|
||||
label: 'Project Number',
|
||||
inputType: 'text',
|
||||
inputType: 'text' as const,
|
||||
required: true,
|
||||
placeholder: '123456789',
|
||||
helpText: 'Your GCP project number (not project ID)',
|
||||
@@ -199,7 +177,7 @@ export const BACKEND_REGISTRY = {
|
||||
{
|
||||
key: 'service_account_credentials',
|
||||
label: 'Service Account JSON',
|
||||
inputType: 'password',
|
||||
inputType: 'password' as const,
|
||||
required: true,
|
||||
placeholder: '{"type":"service_account","project_id":"..."}',
|
||||
helpText: 'Paste the full content of your service account JSON key file',
|
||||
@@ -207,49 +185,15 @@ export const BACKEND_REGISTRY = {
|
||||
},
|
||||
],
|
||||
},
|
||||
sftp: {
|
||||
displayName: 'SFTP',
|
||||
description: 'SSH File Transfer Protocol',
|
||||
fields: [
|
||||
{
|
||||
key: 'host',
|
||||
label: 'Host',
|
||||
inputType: 'text',
|
||||
required: true,
|
||||
placeholder: 'sftp.example.com',
|
||||
helpText: 'The SSH server hostname or IP address',
|
||||
},
|
||||
{
|
||||
key: 'user',
|
||||
label: 'Username',
|
||||
inputType: 'text',
|
||||
required: true,
|
||||
placeholder: 'admin',
|
||||
},
|
||||
{
|
||||
key: 'pass',
|
||||
label: 'Password',
|
||||
inputType: 'password',
|
||||
required: false,
|
||||
helpText: 'SFTP password. Note: rclone may require the password to be obscured using `rclone obscure <password>`. If authentication fails, use the obscured value instead of the plain password.',
|
||||
},
|
||||
{
|
||||
key: 'key_pem',
|
||||
label: 'Private Key (PEM)',
|
||||
inputType: 'password',
|
||||
required: false,
|
||||
helpText: 'Paste your private key in PEM format (-----BEGIN ... PRIVATE KEY-----)',
|
||||
},
|
||||
],
|
||||
},
|
||||
b2: {
|
||||
displayName: 'Backblaze B2',
|
||||
description: 'Backblaze B2 Cloud Storage',
|
||||
category: 'cloud-object-storage' as const,
|
||||
fields: [
|
||||
{
|
||||
key: 'account',
|
||||
label: 'Application Key ID',
|
||||
inputType: 'text',
|
||||
inputType: 'text' as const,
|
||||
required: true,
|
||||
placeholder: 'your-application-key-id',
|
||||
helpText: 'The applicationKeyId — not the master account ID',
|
||||
@@ -258,11 +202,441 @@ export const BACKEND_REGISTRY = {
|
||||
{
|
||||
key: 'key',
|
||||
label: 'Application Key',
|
||||
inputType: 'password',
|
||||
inputType: 'password' as const,
|
||||
required: true,
|
||||
helpText: 'The application key (secret value from the B2 dashboard)',
|
||||
tooltipText: 'The application key value is shown only once when you create a new app key in B2 > App Keys. Copy it immediately — it cannot be retrieved later. If lost, delete the key and create a new one.',
|
||||
},
|
||||
],
|
||||
},
|
||||
} as Record<BackendType, { displayName: string; description: string; fields: FieldDef[] }>;
|
||||
'azure-files': {
|
||||
displayName: 'Azure Files',
|
||||
description: 'Microsoft Azure Files (SMB/REST cloud file shares)',
|
||||
category: 'cloud-object-storage' as const,
|
||||
fields: [
|
||||
{
|
||||
key: 'account',
|
||||
label: 'Storage Account Name',
|
||||
inputType: 'text' as const,
|
||||
required: true,
|
||||
placeholder: 'mystorageaccount',
|
||||
helpText: 'The Azure storage account name',
|
||||
validate: {
|
||||
regex: /^[a-z0-9]{3,24}$/,
|
||||
message: 'Must be 3–24 lowercase alphanumeric characters',
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'key',
|
||||
label: 'Storage Account Key',
|
||||
inputType: 'password' as const,
|
||||
required: true,
|
||||
helpText: 'The base64-encoded storage account key from the Azure portal',
|
||||
tooltipText: 'Found in Azure Portal > your storage account > Security + Networking > Access keys. Use key1 or key2 — either works.',
|
||||
},
|
||||
],
|
||||
},
|
||||
swift: {
|
||||
displayName: 'OpenStack Swift',
|
||||
description: 'OpenStack Swift object storage',
|
||||
category: 'cloud-object-storage' as const,
|
||||
fields: [
|
||||
{
|
||||
key: 'user',
|
||||
label: 'Username',
|
||||
inputType: 'text' as const,
|
||||
required: true,
|
||||
helpText: 'The OpenStack username (or tenant:user for v2 auth)',
|
||||
},
|
||||
{
|
||||
key: 'key',
|
||||
label: 'API Key / Password',
|
||||
inputType: 'password' as const,
|
||||
required: true,
|
||||
helpText: 'The OpenStack API key or password for this user',
|
||||
},
|
||||
{
|
||||
key: 'auth',
|
||||
label: 'Auth URL',
|
||||
inputType: 'text' as const,
|
||||
required: true,
|
||||
placeholder: 'https://auth.example.com/v3',
|
||||
helpText: 'The OpenStack identity (Keystone) auth endpoint URL',
|
||||
tooltipText: 'This is the Keystone endpoint for your OpenStack provider (v2 or v3). Check your provider\'s dashboard or ask your administrator.',
|
||||
},
|
||||
{
|
||||
key: 'tenant',
|
||||
label: 'Tenant / Project Name',
|
||||
inputType: 'text' as const,
|
||||
required: true,
|
||||
helpText: 'The OpenStack tenant (v2) or project name (v3)',
|
||||
},
|
||||
{
|
||||
key: 'region',
|
||||
label: 'Region',
|
||||
inputType: 'text' as const,
|
||||
required: false,
|
||||
helpText: 'The OpenStack region (optional — leave blank if your provider has a single region)',
|
||||
},
|
||||
],
|
||||
},
|
||||
onedrive: {
|
||||
displayName: 'OneDrive',
|
||||
description: 'Microsoft OneDrive (paste pre-obtained rclone token)',
|
||||
category: 'cloud-drives' as const,
|
||||
fields: [
|
||||
{
|
||||
key: 'token',
|
||||
label: 'OAuth Token (JSON)',
|
||||
inputType: 'password' as const,
|
||||
required: true,
|
||||
placeholder: '{"access_token":"...","token_type":"Bearer","refresh_token":"...","expiry":"..."}',
|
||||
helpText: 'Paste the JSON token from: rclone authorize "onedrive"',
|
||||
tooltipText: 'This is the JSON token obtained by running `rclone authorize "onedrive"` on a machine with a browser. The command opens a browser window, you authenticate, and rclone prints a JSON token — paste that entire JSON blob here.',
|
||||
},
|
||||
{
|
||||
key: 'drive_id',
|
||||
label: 'Drive ID',
|
||||
inputType: 'text' as const,
|
||||
required: true,
|
||||
placeholder: 'b!...',
|
||||
helpText: 'The drive ID from your OneDrive. Found in the rclone authorize output.',
|
||||
tooltipText: 'The drive ID appears in the JSON output of `rclone authorize "onedrive"` — look for the "drive_id" field in the response. It typically starts with "b!" for business/SharePoint drives. Personal OneDrive drive IDs look like a UUID.',
|
||||
},
|
||||
{
|
||||
key: 'drive_type',
|
||||
label: 'Drive Type',
|
||||
inputType: 'select' as const,
|
||||
required: true,
|
||||
options: [
|
||||
{ value: 'personal', label: 'Personal' },
|
||||
{ value: 'business', label: 'Business' },
|
||||
{ value: 'documentLibrary', label: 'SharePoint Document Library' },
|
||||
],
|
||||
helpText: 'Personal for consumer OneDrive, Business for Microsoft 365',
|
||||
},
|
||||
],
|
||||
},
|
||||
gdrive: {
|
||||
displayName: 'Google Drive',
|
||||
description: 'Google Drive (paste pre-obtained rclone token or service account)',
|
||||
category: 'cloud-drives' as const,
|
||||
fields: [
|
||||
{
|
||||
key: 'token',
|
||||
label: 'OAuth Token (JSON)',
|
||||
inputType: 'password' as const,
|
||||
required: false,
|
||||
helpText: 'Paste the JSON token from: rclone authorize "drive". Use this OR a service account JSON, not both.',
|
||||
tooltipText: 'Run `rclone authorize "drive"` on a machine with a browser. A browser window opens, you sign in with Google, and rclone prints a JSON token — paste that entire JSON blob here.',
|
||||
},
|
||||
{
|
||||
key: 'service_account_credentials',
|
||||
label: 'Service Account JSON',
|
||||
inputType: 'password' as const,
|
||||
required: false,
|
||||
helpText: 'For unattended/server use: paste the full service account JSON key file content. Use this OR an OAuth token, not both.',
|
||||
tooltipText: 'Create a service account at Google Cloud Console > IAM & Admin > Service Accounts, share the target Drive with that service account email, then download the JSON key and paste its contents here.',
|
||||
},
|
||||
{
|
||||
key: 'root_folder_id',
|
||||
label: 'Root Folder ID',
|
||||
inputType: 'text' as const,
|
||||
required: false,
|
||||
helpText: 'Optional: restrict rclone to a specific folder. Leave blank to access the full Drive.',
|
||||
tooltipText: 'The folder ID is the last segment of the Google Drive folder URL: https://drive.google.com/drive/folders/{FOLDER_ID}',
|
||||
},
|
||||
],
|
||||
},
|
||||
dropbox: {
|
||||
displayName: 'Dropbox',
|
||||
description: 'Dropbox (paste pre-obtained rclone token)',
|
||||
category: 'cloud-drives' as const,
|
||||
fields: [
|
||||
{
|
||||
key: 'token',
|
||||
label: 'OAuth Token (JSON)',
|
||||
inputType: 'password' as const,
|
||||
required: true,
|
||||
helpText: 'Paste the JSON token from: rclone authorize "dropbox"',
|
||||
tooltipText: 'Run `rclone authorize "dropbox"` on a machine with a browser. Sign in to Dropbox when the browser opens, then paste the resulting JSON token here.',
|
||||
},
|
||||
],
|
||||
},
|
||||
box: {
|
||||
displayName: 'Box',
|
||||
description: 'Box cloud storage (paste pre-obtained rclone token)',
|
||||
category: 'cloud-drives' as const,
|
||||
fields: [
|
||||
{
|
||||
key: 'token',
|
||||
label: 'OAuth Token (JSON)',
|
||||
inputType: 'password' as const,
|
||||
required: true,
|
||||
helpText: 'Paste the JSON token from: rclone authorize "box"',
|
||||
tooltipText: 'Run `rclone authorize "box"` on a machine with a browser. Sign in to Box when the browser opens, then paste the resulting JSON token here.',
|
||||
},
|
||||
{
|
||||
key: 'box_sub_type',
|
||||
label: 'Account Type',
|
||||
inputType: 'select' as const,
|
||||
required: false,
|
||||
options: [
|
||||
{ value: 'user', label: 'User account (default)' },
|
||||
{ value: 'enterprise', label: 'Enterprise / Service Account' },
|
||||
],
|
||||
helpText: 'Use Enterprise for Box App Users or service accounts',
|
||||
},
|
||||
],
|
||||
},
|
||||
pcloud: {
|
||||
displayName: 'pCloud',
|
||||
description: 'pCloud cloud storage (paste pre-obtained rclone token)',
|
||||
category: 'cloud-drives' as const,
|
||||
fields: [
|
||||
{
|
||||
key: 'token',
|
||||
label: 'OAuth Token (JSON)',
|
||||
inputType: 'password' as const,
|
||||
required: true,
|
||||
helpText: 'Paste the JSON token from: rclone authorize "pcloud"',
|
||||
tooltipText: 'Run `rclone authorize "pcloud"` on a machine with a browser. Sign in to pCloud when the browser opens, then paste the resulting JSON token here.',
|
||||
},
|
||||
{
|
||||
key: 'hostname',
|
||||
label: 'Server Region',
|
||||
inputType: 'select' as const,
|
||||
required: false,
|
||||
options: [
|
||||
{ value: 'api.pcloud.com', label: 'US (default)' },
|
||||
{ value: 'eapi.pcloud.com', label: 'EU' },
|
||||
],
|
||||
helpText: 'Select EU if your pCloud account is registered in Europe',
|
||||
tooltipText: 'pCloud has separate server infrastructure for US and EU users. EU-registered accounts must use eapi.pcloud.com — using the wrong region will return authentication errors.',
|
||||
},
|
||||
],
|
||||
},
|
||||
sftp: {
|
||||
displayName: 'SFTP',
|
||||
description: 'SSH File Transfer Protocol',
|
||||
category: 'protocol-based' as const,
|
||||
fields: [
|
||||
{
|
||||
key: 'host',
|
||||
label: 'Host',
|
||||
inputType: 'text' as const,
|
||||
required: true,
|
||||
placeholder: 'sftp.example.com',
|
||||
helpText: 'The SSH server hostname or IP address',
|
||||
},
|
||||
{
|
||||
key: 'user',
|
||||
label: 'Username',
|
||||
inputType: 'text' as const,
|
||||
required: true,
|
||||
placeholder: 'admin',
|
||||
},
|
||||
{
|
||||
key: 'pass',
|
||||
label: 'Password',
|
||||
inputType: 'password' as const,
|
||||
required: false,
|
||||
helpText: 'SFTP password. Note: rclone may require the password to be obscured using `rclone obscure <password>`. If authentication fails, use the obscured value instead of the plain password.',
|
||||
},
|
||||
{
|
||||
key: 'key_pem',
|
||||
label: 'Private Key (PEM)',
|
||||
inputType: 'password' as const,
|
||||
required: false,
|
||||
helpText: 'Paste your private key in PEM format (-----BEGIN ... PRIVATE KEY-----)',
|
||||
},
|
||||
],
|
||||
},
|
||||
ftp: {
|
||||
displayName: 'FTP',
|
||||
description: 'File Transfer Protocol (supports plain FTP and FTPS)',
|
||||
category: 'protocol-based' as const,
|
||||
fields: [
|
||||
{
|
||||
key: 'host',
|
||||
label: 'Host',
|
||||
inputType: 'text' as const,
|
||||
required: true,
|
||||
placeholder: 'ftp.example.com',
|
||||
helpText: 'The FTP server hostname or IP address',
|
||||
},
|
||||
{
|
||||
key: 'user',
|
||||
label: 'Username',
|
||||
inputType: 'text' as const,
|
||||
required: false,
|
||||
placeholder: 'anonymous',
|
||||
helpText: 'Leave blank or enter "anonymous" for anonymous FTP access',
|
||||
},
|
||||
{
|
||||
key: 'pass',
|
||||
label: 'Password',
|
||||
inputType: 'password' as const,
|
||||
required: false,
|
||||
helpText: 'FTP password. Leave blank for anonymous access.',
|
||||
},
|
||||
{
|
||||
key: 'port',
|
||||
label: 'Port',
|
||||
inputType: 'text' as const,
|
||||
required: false,
|
||||
placeholder: '21',
|
||||
helpText: 'FTP port (default: 21)',
|
||||
},
|
||||
{
|
||||
key: 'explicit_tls',
|
||||
label: 'TLS Mode',
|
||||
inputType: 'select' as const,
|
||||
required: false,
|
||||
options: [
|
||||
{ value: '', label: 'Plain FTP (no encryption)' },
|
||||
{ value: 'true', label: 'Explicit FTPS (STARTTLS)' },
|
||||
],
|
||||
helpText: 'Use Explicit FTPS for encrypted FTP connections (port 21 + STARTTLS)',
|
||||
},
|
||||
],
|
||||
},
|
||||
webdav: {
|
||||
displayName: 'WebDAV',
|
||||
description: 'WebDAV (NextCloud, SharePoint, OwnCloud, and others)',
|
||||
category: 'protocol-based' as const,
|
||||
fields: [
|
||||
{
|
||||
key: 'url',
|
||||
label: 'WebDAV URL',
|
||||
inputType: 'text' as const,
|
||||
required: true,
|
||||
placeholder: 'https://example.com/dav',
|
||||
helpText: 'The full WebDAV endpoint URL',
|
||||
tooltipText: 'NextCloud: https://yourserver/remote.php/dav/files/username/ | OwnCloud: https://yourserver/remote.php/webdav/ | SharePoint: https://company.sharepoint.com/sites/mysite/Documents',
|
||||
},
|
||||
{
|
||||
key: 'user',
|
||||
label: 'Username',
|
||||
inputType: 'text' as const,
|
||||
required: true,
|
||||
helpText: 'The WebDAV username',
|
||||
},
|
||||
{
|
||||
key: 'pass',
|
||||
label: 'Password',
|
||||
inputType: 'password' as const,
|
||||
required: true,
|
||||
helpText: 'The WebDAV password',
|
||||
},
|
||||
{
|
||||
key: 'vendor',
|
||||
label: 'Vendor / Server Type',
|
||||
inputType: 'select' as const,
|
||||
required: false,
|
||||
options: [
|
||||
{ value: 'nextcloud', label: 'NextCloud' },
|
||||
{ value: 'owncloud', label: 'OwnCloud' },
|
||||
{ value: 'sharepoint', label: 'SharePoint (Microsoft 365 OAuth)' },
|
||||
{ value: 'sharepoint-ntlm', label: 'SharePoint (NTLM / on-premises)' },
|
||||
{ value: 'other', label: 'Other WebDAV server' },
|
||||
],
|
||||
helpText: 'Selecting the correct vendor enables server-specific optimizations',
|
||||
},
|
||||
],
|
||||
},
|
||||
smb: {
|
||||
displayName: 'SMB / Windows Share',
|
||||
description: 'SMB / CIFS Windows file shares',
|
||||
category: 'protocol-based' as const,
|
||||
fields: [
|
||||
{
|
||||
key: 'host',
|
||||
label: 'Host',
|
||||
inputType: 'text' as const,
|
||||
required: true,
|
||||
placeholder: 'fileserver.example.com',
|
||||
helpText: 'The SMB server hostname or IP address',
|
||||
},
|
||||
{
|
||||
key: 'user',
|
||||
label: 'Username',
|
||||
inputType: 'text' as const,
|
||||
required: true,
|
||||
helpText: 'The SMB username (can include domain: DOMAIN\\user)',
|
||||
},
|
||||
{
|
||||
key: 'pass',
|
||||
label: 'Password',
|
||||
inputType: 'password' as const,
|
||||
required: false,
|
||||
helpText: 'The SMB password. Leave blank for guest/anonymous access.',
|
||||
},
|
||||
{
|
||||
key: 'domain',
|
||||
label: 'Domain',
|
||||
inputType: 'text' as const,
|
||||
required: false,
|
||||
placeholder: 'WORKGROUP',
|
||||
helpText: 'Windows domain name (optional, defaults to WORKGROUP)',
|
||||
},
|
||||
{
|
||||
key: 'port',
|
||||
label: 'Port',
|
||||
inputType: 'text' as const,
|
||||
required: false,
|
||||
placeholder: '445',
|
||||
helpText: 'SMB port (default: 445)',
|
||||
},
|
||||
],
|
||||
},
|
||||
http: {
|
||||
displayName: 'HTTP (read-only)',
|
||||
description: 'Read-only access to HTTP/HTTPS file listings',
|
||||
category: 'protocol-based' as const,
|
||||
fields: [
|
||||
{
|
||||
key: 'url',
|
||||
label: 'URL',
|
||||
inputType: 'text' as const,
|
||||
required: true,
|
||||
placeholder: 'https://example.com/path/',
|
||||
helpText: 'The base URL of the HTTP file listing. Must expose directory listings.',
|
||||
tooltipText: 'The HTTP backend is read-only and works with Apache/Nginx directory listings or any server that returns HTML with links. Ensure the URL ends with a trailing slash for directory access.',
|
||||
},
|
||||
],
|
||||
},
|
||||
seafile: {
|
||||
displayName: 'Seafile',
|
||||
description: 'Seafile self-hosted cloud storage',
|
||||
category: 'protocol-based' as const,
|
||||
fields: [
|
||||
{
|
||||
key: 'url',
|
||||
label: 'Server URL',
|
||||
inputType: 'text' as const,
|
||||
required: true,
|
||||
placeholder: 'https://cloud.seafile.com',
|
||||
helpText: 'The Seafile server URL (without trailing slash)',
|
||||
},
|
||||
{
|
||||
key: 'user',
|
||||
label: 'Email / Username',
|
||||
inputType: 'text' as const,
|
||||
required: true,
|
||||
helpText: 'Your Seafile account email address',
|
||||
},
|
||||
{
|
||||
key: 'pass',
|
||||
label: 'Password',
|
||||
inputType: 'password' as const,
|
||||
required: true,
|
||||
helpText: 'Your Seafile account password',
|
||||
},
|
||||
],
|
||||
},
|
||||
} as const;
|
||||
|
||||
// BackendType is derived from registry keys — no manual union needed.
|
||||
// Adding a backend to BACKEND_REGISTRY automatically extends BackendType.
|
||||
export type BackendType = keyof typeof BACKEND_REGISTRY;
|
||||
|
||||
Reference in New Issue
Block a user