How PicList-Core's Configuration Manager Handles and Stores Multiple Configurations
PicList-Core stores multiple uploader configurations in a single, version-aware configuration file using the ConfigManager class located in src/utils/configManager.ts, which automatically migrates legacy single-config formats to a new multi-config schema while maintaining backward compatibility through the picBed field.
PicList-Core, an enhanced fork of the PicGo image uploader maintained at kuingsmile/piclist-core, introduces robust multi-configuration support that allows users to maintain multiple named profiles per uploader (such as GitHub, SM.MS, or Qiniu) within one unified configuration file. The system handles complex configuration state through a centralized ConfigManager utility that provides both programmatic APIs and CLI interfaces for creating, updating, and switching between configuration profiles.
Data Structure and Type Definitions
The configuration system relies on strict TypeScript interfaces defined in src/types/index.ts to ensure type safety across the multi-config architecture.
IConfigItem represents a single configuration entry with metadata and uploader-specific fields:
export interface IConfigItem {
_id: string // Unique identifier
_configName: string // Human-readable name
_createdAt: number // Timestamp
_updatedAt: number // Timestamp
[propName: string]: any // Uploader-specific settings (tokens, paths, etc.)
}
IUploaderConfigList wraps multiple configurations for a specific uploader type and tracks which configuration is currently active:
export interface IUploaderConfigList {
configList: IConfigItem[] // Array of all configs for this uploader
defaultId: string // _id of the currently selected default config
}
The top-level configuration interface IConfig stores the multi-config data under an optional uploader property:
export interface IConfig {
// ... other PicGo settings
uploader?: Record<string, IUploaderConfigList> // Multi-config structure
}
Each uploader (e.g., smms, github, qiniu) maintains an independent entry under uploader.<uploaderName> containing a configList array and a defaultId string pointing to the active configuration.
Core Configuration Management Methods
The ConfigManager class in src/utils/configManager.ts implements a complete CRUD interface for configuration management. All methods automatically invoke migrateToMultiConfig to ensure legacy data compatibility.
Retrieving Configurations
getCurrentUploaderConfig(uploaderName)– Returns the defaultIConfigItemfor the specified uploader by matching_idagainstdefaultId(lines 55-65).getAllUploaderConfigs(uploaderName)– Retrieves the completeconfigListarray for an uploader, enabling users to view all available profiles (lines 67-71).
Modifying Configurations
addUploaderConfig(uploaderName, configName, config)– Creates a newIConfigItemwith auto-generated_id, timestamps, and the providedconfigName. If this is the first configuration for the uploader, it automatically becomes the default and syncs to the legacypicBedfield (lines 74-101).updateUploaderConfig(uploaderName, id, newConfig)– Overwrites an existing configuration matched by_idwhile preserving immutable metadata fields (_id,_createdAt). If updating the default configuration, changes propagate to the legacypicBed.<uploader>location (lines 104-132).deleteUploaderConfig(uploaderName, id)– Removes a configuration fromconfigListwith safety guards: it prevents deletion of the only remaining config for an active uploader and blocks deletion of the current default (users must switch defaults first). After deletion, it cleans up empty uploader entries (lines 134-173).
Managing Defaults and Metadata
setDefaultConfig(uploaderName, id)– Switches thedefaultIdto the specified configuration_idand immediately syncs the selected config topicBed.<uploader>to maintain compatibility with legacy plugins (lines 175-193).renameConfig(uploaderName, id, newName)– Updates_configNameand_updatedAttimestamp. If renaming the default configuration, the change also propagates to the legacy sync (lines 209-230).
Migration Strategy for Legacy Configurations
Older PicGo versions stored single configurations under picBed.<uploader>. The migrateToMultiConfig method (lines 12-53 in src/utils/configManager.ts) automatically handles upgrades without breaking existing setups.
The migration process executes when first accessing an uploader:
- Detection – Reads legacy configuration via
this.ctx.getConfig(picBed.${uploaderName}). - Early Exit – If the new
uploadersection already contains data for this uploader, the function returns immediately to avoid overwriting. - Structure Creation – Constructs a new
IUploaderConfigList:- If legacy config exists with data, it becomes the first entry in
configListwithdefaultIdpointing to it. - If no legacy data exists, creates an empty list with
defaultIdset to an empty string.
- If legacy config exists with data, it becomes the first entry in
- Dual Storage – Preserves the original config under
picBed.<uploader>for backward compatibility while saving the new structure underuploader.<uploader>.
This dual-write strategy ensures existing plugins reading the old picBed shape continue functioning, while new code leverages the multi-config capabilities.
CLI Interface for Configuration Management
The commander plugin at src/plugins/commander/configManager.ts exposes ConfigManager functionality through terminal commands, wrapping the programmatic methods with user-friendly interfaces:
config-list– Displays all configurations for an uploader usinggetAllUploaderConfigsand highlights the current default viagetCurrentUploaderConfig.config-use– Switches active configurations by callingsetDefaultConfig.config-remove– Deletes configurations throughdeleteUploaderConfigwith appropriate validation.config-rename– Updates configuration names usingrenameConfig.
These commands provide direct access to the configuration management system without requiring JavaScript programming knowledge.
Programmatic Usage Examples
The following TypeScript example demonstrates complete configuration lifecycle management using the ConfigManager API:
import PicGo from '../core/PicGo'
import { ConfigManager } from '../utils/configManager'
// Initialize PicGo context and ConfigManager
const ctx = new PicGo()
const cfgMgr = new ConfigManager(ctx)
// Add a new GitHub configuration
const githubCfg = cfgMgr.addUploaderConfig('github', 'Work Account', {
repo: 'company/images',
branch: 'main',
token: 'ghp_xxxxxxxxxxxx'
})
// List all GitHub configurations with default indicator
const allConfigs = cfgMgr.getAllUploaderConfigs('github')
const current = cfgMgr.getCurrentUploaderConfig('github')
allConfigs.forEach(cfg => {
const marker = cfg._id === current?._id ? ' [DEFAULT]' : ''
console.log(`- ${cfg._configName}${marker} (${cfg._id})`)
})
// Switch to a different configuration
if (allConfigs.length > 1) {
cfgMgr.setDefaultConfig('github', allConfigs[1]._id)
console.log(`Switched default to: ${allConfigs[1]._configName}`)
}
// Update configuration details
cfgMgr.updateUploaderConfig('github', githubCfg._id, {
token: 'ghp_newtoken_value',
_configName: githubCfg._configName // Preserve original name
})
// Safely delete a non-default configuration
const toDelete = allConfigs.find(c => c._id !== current?._id)
if (toDelete) {
cfgMgr.deleteUploaderConfig('github', toDelete._id)
}
All methods internally trigger migrateToMultiConfig, ensuring seamless upgrades from legacy single-config formats during any operation.
Summary
- PicList-Core stores multiple uploader configurations in a unified file structure under the
uploaderproperty, with each uploader maintaining aconfigListarray and adefaultIdpointer. - The
ConfigManagerclass insrc/utils/configManager.tsprovides atomic CRUD operations, default management, and automatic migration from legacypicBedformats. - Backward compatibility is maintained through dual-write synchronization to the legacy
picBed.<uploader>field, ensuring existing plugins continue functioning. - Configurations include immutable metadata (
_id,_createdAt) and mutable display names (_configName), with safety guards preventing deletion of the last or default configuration. - Both programmatic APIs and CLI commands (via
src/plugins/commander/configManager.ts) provide full access to configuration management capabilities.
Frequently Asked Questions
Where does PicList-Core physically store the configuration file?
PicList-Core utilizes PicGo's standard configuration storage mechanism, typically reading from and writing to the user's home directory configuration file (the exact path depends on the operating system and PicGo's config resolution). The ConfigManager accesses this through the PicGo context (this.ctx), treating it as a single JSON file containing both the legacy picBed structure and the new uploader multi-config structure.
How does the migration from single-config to multi-config work?
When the ConfigManager first accesses an uploader, it automatically invokes migrateToMultiConfig (lines 12-53). This method detects legacy data stored under picBed.<uploader> and transforms it into the new uploader.<uploader> structure with a configList containing the legacy config as the first entry. The original picBed data is preserved for backward compatibility, while the new structure enables multiple configurations.
Can I use multiple configurations simultaneously for different upload operations?
No, PicList-Core maintains a single default configuration per uploader at any given time, identified by defaultId. While you can store multiple configurations in configList, active operations use whichever configuration is currently set as default. You must switch defaults using setDefaultConfig (or the config-use CLI command) to change which configuration applies to subsequent uploads.
Is it safe to delete the legacy picBed configuration entries?
Deleting legacy picBed entries is not recommended because ConfigManager relies on this field for backward compatibility synchronization. The private syncConfigToPicBed method (lines 196-200) continuously updates picBed.<uploader> to match the current default configuration, ensuring that legacy plugins and external tools reading the old format receive the correct active settings. Removing this field would break compatibility with standard PicGo plugins.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →