@flowscripter/dynamic-cli-framework
    Preparing search index...

    Class KeyValueServiceProvider

    Provides a generic, per-scope key-value store for commands and services (KeyValueService).

    The underlying data is read from/written to the same configuration file managed by ConfigurationServiceProvider - see ConfigurationServiceProvider.getKeyValueData and ConfigurationServiceProvider.flushIfDirty, reached via a direct constructor reference wired up by BaseCLI (never via Context, since that would expose config-file read/write access more broadly than intended).

    Its serviceId is KEY_VALUE_SERVICE_ID and its ServiceInfo.service is a placeholder (UnreachableKeyValueService) - real access always goes through a per-consumer decorated Context from getContextForScope, applied by runner.ts.

    Any node within a value passed to KeyValueService.set can be wrapped in Secret - at any depth - to have that node, and only that node, stored as an OS-native secret. When a node is wrapped in Secret, its value (of any shape) is JSON-serialized and stored as a single OS-native secret via Bun.secrets, with a sentinel value of the format __SECRET__:<bun_secret_name> substituted in its place in the structure that gets stored in the config file. Everything else in the value is stored as plain (unencrypted) config data. The sentinel prefix __SECRET__: is reserved and must not be used for regular key-value data.

    Independently of how a value was written, KeyValueService.get recursively resolves any string leaf - at any depth within the retrieved value - which starts with the sentinel prefix, via the OS secret store. This means a secret reference may also be hand-embedded (nested arbitrarily deep) directly within a plain, non-secret value in the config file.

    Secret support requires secretServiceEnabled=true in the constructor (which also requires keyValueServiceEnabled=true on the ConfigurationServiceProvider to have config enabled).

    As an example of the underlying config file structure:

    {
    "defaults": {
    ...
    },
    "key-values": {
    "commands": {
    "command1": {
    "foo1": "bar1",
    "foo2": "__SECRET__:command_command1_foo2",
    "foo3": {
    "nested": ["a", "__SECRET__:command_command1_foo3_nested"]
    }
    },
    "command2": {
    "foo1": "bar3"
    }
    },
    "services": {
    "service-id-1": {
    "foo1": "bar"
    }
    }
    }
    }

    Implements

    Index
    keyValueServiceEnabled: boolean
    secretServiceEnabled: boolean
    serviceId: string = KEY_VALUE_SERVICE_ID

    The ID which identifies the service provided.

    servicePriority: number

    Used to determine the order in which multiple service instances will be initialised. Higher values will be initialised before lower values.

    • Return a Context which delegates every lookup to context unchanged, except getServiceById(KEY_VALUE_SERVICE_ID), which resolves to the scope-bound instance from getScopedKeyValueService for the given scope. Used by runner.ts to give each command/service/task a KeyValueService isolated to its own scope, invisibly at the call site.

      Returns context itself, unchanged, if neither keyValueServiceEnabled nor secretServiceEnabled is set.

      Also forwards addServiceInstance, even though it is not part of the Context interface: runner.ts applies this same scoping to every ServiceProvider's initService() call (scope "service"), and PluginServiceProvider.initService() relies on casting its received context to DefaultContext to register services discovered from plugins at runtime.

      Parameters

      Returns Context