b2c_tooling_sdk.config
Configuration loading utilities.
Mirrors src/config/index.ts. The preferred high-level API is resolve_config, which returns a rich ResolvedConfigImpl with validation predicates and auth-strategy factory methods.
Resolution priority (highest to lowest): explicit overrides, then configuration sources (dw.json, ~/.mobify, package.json). Later sources only fill in missing values. Hostname-mismatch protection prevents mixing credentials across instances.
To go straight from configuration to a usable client, use create_instance_from_config or ResolvedConfigImpl.create_b2c_instance.
Example:
from b2c_tooling_sdk.config import resolve_config
from b2c_tooling_sdk.config.types import NormalizedConfig
config = await resolve_config(
NormalizedConfig(hostname="example.com", client_id="...")
)
if config.has_oauth_config():
strategy = config.create_oauth()Classes
ConfigCatalogFile
class ConfigCatalogFileA dw.json file participating in the effective instance catalog.
Fields
| Name | Type |
|---|---|
location | str |
scope | Literal['global', 'primary'] |
selected | bool |
ConfigLoadResult
class ConfigLoadResultResult of loading configuration from a single source.
Fields
| Name | Type | Default |
|---|---|---|
config | NormalizedConfig | |
scope | Literal['global'] | None | None |
instance_catalog | list[ConfigCatalogFile] | None | None |
location | str | None | None |
ConfigResolutionResult
class ConfigResolutionResultResult of configuration resolution.
Fields
| Name | Type |
|---|---|
config | NormalizedConfig |
warnings | list[ConfigWarning] |
sources | list[ConfigSourceInfo] |
ConfigResolver
class ConfigResolverResolves configuration from multiple sources with consistent behaviour.
resolve method
async def resolve(overrides: NormalizedConfig | None = None, options: ResolveConfigOptions | None = None) -> ConfigResolutionResultResolve configuration from all sources, applying override precedence.
create_auth_credentials method
async def create_auth_credentials(overrides: NormalizedConfig | None = None, options: ResolveConfigOptions | None = None) -> AuthCredentialsResolve config and return AuthCredentials for resolve_auth_strategy.
create_instance method
async def create_instance(overrides: NormalizedConfig | None = None, options: ResolveConfigOptions | None = None) -> B2CInstanceResolve configuration and create a B2CInstance.
A convenience method combining resolve with instance creation. Any resolution warnings are logged.
Raises
ValueError— if no hostname is available in the resolved config.
ConfigSource
class ConfigSource(Protocol)A configuration source that can contribute config values.
Implement this protocol to create custom configuration sources. The required surface is name and load. Sources may optionally implement the instance-management and credential-storage methods; consumers probe for them with getattr / hasattr at runtime.
Fields
| Name | Type |
|---|---|
name | str |
load method
def load(options: ResolveConfigOptions) -> MaybePromise[ConfigLoadResult | None]Load configuration from this source (may be sync or async).
ConfigSourceInfo
class ConfigSourceInfoInformation about a configuration source that participated in resolution.
Fields
| Name | Type | Default |
|---|---|---|
name | str | |
fields | list[str] | |
scope | Literal['global'] | None | None |
location | str | None | None |
fields_ignored | list[str] | None | None |
instance_catalog | list[ConfigCatalogFile] | None | None |
ConfigSourceRegistry
class ConfigSourceRegistryRegistry that collects ConfigSource instances for resolution.
Fields
| Name | Type | Description |
|---|---|---|
size | int | Number of registered sources. |
register method
def register(source: ConfigSource) -> NoneRegister a source (ignored if a source with the same name exists).
unregister method
def unregister(name: str) -> boolRemove a source by name; returns True if one was removed.
get_sources method
def get_sources() -> list[ConfigSource]Return a shallow copy of all registered sources.
clear method
def clear() -> NoneRemove all registered sources (primarily useful for testing).
get_source_names method
def get_source_names() -> list[str]Return the names of all registered sources.
ConfigWarning
class ConfigWarningA warning generated during configuration resolution.
Fields
| Name | Type | Default |
|---|---|---|
code | ConfigWarningCode | |
message | str | |
details | dict[str, Any] | None | None |
CreateB2CInstanceOptions
class CreateB2CInstanceOptionsOptions for constructing a B2C instance from resolved configuration.
Fields
| Name | Type | Default |
|---|---|---|
redirect_uri | str | None | None |
open_browser | Callable[[str], Awaitable[None]] | None | None |
oauth_strategy | AuthStrategy | Callable[[], AuthStrategy] | None | None |
CreateInstanceOptions
class CreateInstanceOptionsOptions for creating an instance in a dw.json-style source.
Flattens the TypeScript CreateInstanceOptions & ResolveConfigOptions intersection: it carries the instance name/config plus the subset of resolution fields a dw.json source needs to locate the target file.
Fields
| Name | Type | Default |
|---|---|---|
name | str | |
config | NormalizedConfig | |
set_active | bool | False |
config_path | str | None | None |
project_directory | str | None | None |
working_directory | str | None | None |
default_config_path | str | None | None |
CreateOAuthOptions
class CreateOAuthOptionsOptions for creating an OAuth auth strategy.
Fields
| Name | Type | Default |
|---|---|---|
allowed_methods | list[AuthMethod] | None | None |
scopes | list[str] | None | None |
redirect_uri | str | None | None |
open_browser | Callable[[str], Awaitable[None]] | None | None |
DwJsonSource
class DwJsonSourceConfiguration source that loads from dw.json files.
load method
async def load(options: ResolveConfigOptions) -> ConfigLoadResult | NoneLoad configuration for the requested (or active/root) instance.
list_instances method
async def list_instances(options: ResolveConfigOptions | None = None) -> list[InstanceInfo]List all instances across the effective dw.json files (deduped by name).
create_instance method
async def create_instance(options: CreateInstanceOptions) -> NoneCreate a new instance in dw.json.
remove_instance method
async def remove_instance(name: str, options: ResolveConfigOptions | None = None) -> NoneRemove an instance from the dw.json file that contains it.
set_active_instance method
async def set_active_instance(name: str, options: ResolveConfigOptions | None = None) -> NoneSet an instance active, clearing active flags in the other catalog files.
EnvSource
class EnvSourceConfiguration source that reads CLI configuration environment variables.
Priority -10 (higher than dw.json at 0), matching CLI behaviour where env vars override file-based config.
load method
def load(options: ResolveConfigOptions) -> ConfigLoadResult | NoneLoad config from environment variables (synchronous).
InstanceInfo
class InstanceInfoInformation about a configured instance.
Fields
| Name | Type | Default |
|---|---|---|
name | str | |
source | str | |
hostname | str | None | None |
active | bool | None | None |
location | str | None | None |
InstanceManager
class InstanceManagerAggregates instance-management operations across multiple config sources.
list_all_instances method
async def list_all_instances(options: ResolveConfigOptions | None = None) -> list[InstanceInfo]List instances from every source that implements list_instances.
get_instance_sources method
def get_instance_sources() -> list[ConfigSource]Return sources that can create instances.
get_credential_sources method
def get_credential_sources(field: str) -> list[ConfigSource]Return sources that can store the given credential field.
create_instance method
async def create_instance(options: CreateInstanceOptions, target_source: str | None = None) -> NoneCreate an instance in the target source (or the first available one).
remove_instance method
async def remove_instance(name: str, options: ResolveConfigOptions | None = None) -> NoneRemove an instance from whichever source contains it.
set_active_instance method
async def set_active_instance(name: str, options: ResolveConfigOptions | None = None) -> NoneSet an instance active in whichever source contains it.
store_credential method
async def store_credential(instance_name: str, field: str, value: str, target_source: str | None = None, options: ResolveConfigOptions | None = None) -> NoneStore a credential for an instance in the target credential source.
LibraryEntry
class LibraryEntryA configured content library entry.
The simpler str form (an ID alone) is equivalent to LibraryEntry(id=..., site_library=False).
Fields
| Name | Type | Default |
|---|---|---|
id | str | |
site_library | bool | False |
LoadDwJsonResult
class LoadDwJsonResultThe selected dw.json config plus the file path it came from.
Fields
| Name | Type |
|---|---|
config | DwJsonConfig |
path | str |
NormalizedConfig
class NormalizedConfigNormalized B2C configuration with snake_case fields.
The canonical intermediate format that all configuration sources map to, regardless of their on-disk format (dw.json kebab/camelCase, env vars, etc.).
Fields
| Name | Type | Default |
|---|---|---|
hostname | str | None | None |
webdav_hostname | str | None | None |
code_version | str | None | None |
username | str | None | None |
password | str | None | None |
client_id | str | None | None |
client_secret | str | None | None |
scopes | list[str] | None | None |
auth_methods | list[AuthMethod] | None | None |
account_manager_host | str | None | None |
jwt_cert_path | str | None | None |
jwt_key_path | str | None | None |
jwt_passphrase | str | None | None |
slas_client_id | str | None | None |
slas_client_secret | str | None | None |
site_id | str | None | None |
short_code | str | None | None |
tenant_id | str | None | None |
sandbox_api_host | str | None | None |
realm | str | None | None |
mrt_project | str | None | None |
mrt_environment | str | None | None |
mrt_api_key | str | None | None |
mrt_origin | str | None | None |
auto_upload | bool | None | None |
cartridges | list[str] | None | None |
import_set_exclude | list[str] | None | None |
content_library | str | None | None |
catalogs | list[str] | None | None |
libraries | list[str | LibraryEntry] | None | None |
asset_query | list[str] | None | None |
cip_host | str | None | None |
docs_categories | list[str] | None | None |
instance_name | str | None | None |
project_directory | str | None | None |
working_directory | str | None | None |
certificate | str | None | None |
certificate_passphrase | str | None | None |
self_signed | bool | None | None |
api_backend | Literal['ocapi', 'scapi', 'auto'] | None | None |
ResolveConfigOptions
class ResolveConfigOptionsOptions for configuration resolution.
Fields
| Name | Type | Default |
|---|---|---|
instance | str | None | None |
config_path | str | None | None |
default_config_path | str | None | None |
project_directory | str | None | None |
working_directory | str | None | None |
hostname_protection | bool | None | None |
client_id_protection | bool | None | None |
cloud_origin | str | None | None |
credentials_file | str | None | None |
account_manager_host | str | None | None |
sources_before | list[ConfigSource] | None | None |
sources_after | list[ConfigSource] | None | None |
replace_default_sources | bool | False |
ResolvedConfigImpl
class ResolvedConfigImplResolved configuration with validation and auth-strategy factories.
has_b2c_instance_config method
def has_b2c_instance_config() -> boolWhether a B2C instance can be created (requires a hostname).
has_mrt_config method
def has_mrt_config() -> boolWhether MRT credentials are available (requires an MRT API key).
has_oauth_config method
def has_oauth_config() -> boolWhether OAuth can be used (requires a client id).
has_basic_auth_config method
def has_basic_auth_config() -> boolWhether basic auth can be used (requires username and password).
create_b2c_instance method
def create_b2c_instance(options: CreateB2CInstanceOptions | None = None) -> B2CInstanceCreate a B2CInstance from the resolved config.
Raises
ValueError— if no hostname is available (seehas_b2c_instance_config).
create_basic_auth method
def create_basic_auth() -> AuthStrategyCreate a BasicAuthStrategy from the resolved credentials.
create_oauth method
def create_oauth(options: CreateOAuthOptions | None = None) -> AuthStrategyCreate an OAuth strategy, merging any additional scopes over config scopes.
create_mrt_auth method
def create_mrt_auth() -> AuthStrategyCreate an ApiKeyStrategy for MRT (Authorization header).
create_webdav_auth method
def create_webdav_auth() -> AuthStrategyCreate the best available WebDAV auth strategy (basic preferred, else OAuth).
Functions
add_instance
def add_instance(instance: DwJsonConfig, *, path: str | None = None, project_directory: str | None = None, working_directory: str | None = None, set_active: bool = False) -> NoneAdd a new named instance to dw.json, creating the file if needed.
Raises
ValueError— if the instance has no name or the name already exists.
create_config_resolver
def create_config_resolver() -> ConfigResolverCreate a ConfigResolver with the default sources.
create_instance_from_config
def create_instance_from_config(config: NormalizedConfig, options: CreateB2CInstanceOptions | None = None) -> B2CInstanceCreate a B2CInstance from a NormalizedConfig.
Single source of truth for instance creation from resolved configuration — used by both ResolvedConfigImpl.create_b2c_instance and consumers such as CLI commands. TLS options are included only when a certificate or self-signed mode is configured. When options supplies a redirect_uri or open_browser, they are injected into the OAuth config for browser flows.
Raises
ValueError— ifconfighas nohostname.
create_instance_manager
def create_instance_manager(sources: list[ConfigSource]) -> InstanceManagerCreate an InstanceManager with the given sources.
find_dw_json
def find_dw_json(project_directory: str | None = None) -> str | NoneFind dw.json by searching upward from project_directory (defaults to cwd).
get_b2c_config_directory
def get_b2c_config_directory(*, config_directory: str | None = None, environment: dict[str, str] | None = None, home_directory: str | None = None, platform: str | None = None) -> strResolve the shared oclif-compatible B2C configuration directory.
get_b2c_settings_path
def get_b2c_settings_path(*, config_directory: str | None = None, environment: dict[str, str] | None = None, home_directory: str | None = None, platform: str | None = None) -> strResolve the shared settings.json path.
is_sensitive_config_field
def is_sensitive_config_field(field: str) -> boolReturn True when a field name holds a secret that should be masked.
load_dw_json
def load_dw_json(*, instance: str | None = None, path: str | None = None, project_directory: str | None = None, working_directory: str | None = None) -> LoadDwJsonResult | NoneLoad configuration from a dw.json file (no upward directory search).
Keys are normalized to camelCase and the appropriate instance is selected. Returns None if no file is found or the named instance is absent. Raises on invalid JSON.
load_full_dw_json
def load_full_dw_json(*, path: str | None = None, project_directory: str | None = None, working_directory: str | None = None) -> LoadFullDwJsonResult | NoneLoad the raw multi-config dw.json without selecting an instance.
Returns None if the file does not exist. Raises on invalid JSON.
mask_config_value
def mask_config_value(value: str) -> strMask a secret, showing the first 4 chars when long enough to aid identification.
Matches the SDK logger convention (<first4>...REDACTED); values of 10 or fewer characters are fully redacted.
merge_project_environment
def merge_project_environment(project_environment: dict[str, str] | None = None, ambient_environment: dict[str, str] | None = None) -> dict[str, str]Merge project variables with the ambient environment (ambient wins).
normalize_config_keys
def normalize_config_keys(raw: dict[str, Any]) -> dict[str, Any]Normalize config keys to their canonical camelCase form.
Resolution order per key: alias table, then kebab->camelCase conversion. The first value wins when multiple keys resolve to the same canonical name. None values are dropped (mirrors the TS undefined skip) so absent keys never shadow a later alias for the same canonical name.
read_b2c_settings
def read_b2c_settings(*, config_directory: str | None = None, environment: dict[str, str] | None = None, home_directory: str | None = None, platform: str | None = None) -> dict[str, Any]Read shared B2C settings. Missing or invalid files are treated as unset.
A relative defaultConfigPath is resolved against the settings directory; a non-string/empty value is dropped with a warning.
read_project_environment
def read_project_environment(project_directory: str | None = None) -> dict[str, str] | NoneRead all variables from a project's .env file, or None if absent.
redact_config_values
def redact_config_values(values: NormalizedConfig, *, unmask: bool = False) -> dict[str, Any]Return a dict of config values with sensitive fields masked.
Fields whose value is None are omitted. When unmask is True secrets are shown verbatim.
remove_instance
def remove_instance(name: str, *, path: str | None = None, project_directory: str | None = None, working_directory: str | None = None) -> NoneRemove a named instance from dw.json.
Raises
FileNotFoundError— if no dw.json exists.ValueError— when removing the root instance or a missing instance.
resolve_config
async def resolve_config(overrides: NormalizedConfig | None = None, options: ResolveConfigOptions | None = None) -> ResolvedConfigImplResolve configuration and return a rich ResolvedConfigImpl.
Resolution priority (highest to lowest): explicit overrides, sources_before, default sources (dw.json, ~/.mobify, package.json), sources_after, and globally-registered sources. Set options.replace_default_sources to omit the defaults.
resolve_library_entries
def resolve_library_entries(libraries: list[str | LibraryEntry] | None) -> list[LibraryEntry]Normalize a libraries value to LibraryEntry objects.
Bare strings become LibraryEntry(id=..., site_library=False). Returns an empty list when the input is None.
save_dw_json
def save_dw_json(config: DwJsonMultiConfig, file_path: str) -> NoneSave a dw.json to disk (2-space indent + trailing newline).
set_active_instance
def set_active_instance(name: str, *, path: str | None = None, project_directory: str | None = None, working_directory: str | None = None) -> NoneSet a named instance as the active default.
Raises
FileNotFoundError— if no dw.json exists.ValueError— if the instance is not found.
write_b2c_settings
def write_b2c_settings(settings: dict[str, Any], *, config_directory: str | None = None, environment: dict[str, str] | None = None, home_directory: str | None = None, platform: str | None = None) -> NoneWrite shared B2C settings atomically (mode 0o600, trailing newline).
Attributes
B2C_SETTINGS_FILENAME
B2C_SETTINGS_FILENAME = 'settings.json'SENSITIVE_CONFIG_FIELDS
SENSITIVE_CONFIG_FIELDS: frozenset[str] = frozenset({'certificate_passphrase', 'client_secret', 'jwt_passphrase', 'mrt_api_key', 'password', 'slas_client_secret'})DwJsonConfig
DwJsonConfig = dict[str, Any]DwJsonMultiConfig
DwJsonMultiConfig = dict[str, Any]ResolvedB2CConfig
ResolvedB2CConfig = ResolvedConfigImplglobal_config_source_registry
global_config_source_registry = ConfigSourceRegistry()