Loads and caches configuration and secrets from AWS services.
@pureskillgg/ace ("AWS Config Executor") is a small Node.js ESM library that
resolves, validates, parses, and caches application configuration and secrets
from AWS SSM Parameter Store, AWS Secrets Manager, environment variables, and
in-memory local values. A service declares the parameters it needs and calls a
single async getConfig; ace fetches them all in parallel, caches them, logs the
resolution, and hands back a plain object of resolved values.
A caller declares a map of named parameters and calls getConfig:
import { ssmString, secretsManagerString, getConfig } from '@pureskillgg/ace'
const parameters = {
bucketArn: ssmString('/app/bucket_arn'),
apiKey: secretsManagerString('/app/api_key')
}
const { bucketArn, apiKey } = await getConfig({ parameters })getConfig({ parameters, aliases, cache, log, ...providerDependencies })
(lib/get-config.js) fetches every entry in parallel (Promise.all over
Object.entries(parameters)) and returns an object of resolved values keyed by
the caller's own names. Each fetch is:
- Cached through cache-manager (
cache.wrap(name, …)). The default cache is in-memory and lives only for one call; to persist values across (e.g.) lambda invocations, pass a sharedcachecreated in the outer scope. Note the cache key is the caller-supplied object key (name), not the resolved SSM/secret path or the alias — two parameters that share a name on a shared cache will collide. - Logged via @pureskillgg/mlabs-logger (Pino) with a child logger carrying
paramName/paramAlias/paramKey/paramProvider. Sensitive values (Secrets Manager) are redacted as[Redacted]in debug logs. On failure each fetch logslog.error({ err }, 'fail')and rethrows.
Each parameter is a Parameter instance (lib/parameter.js) configured with a
provider class, an optional fallback, a parser (default identity), a
validator (default always-true), and an isSensitive flag. On get(key) it
lazily instantiates the provider (initProvider, passed the provider
dependencies from getConfig such as ssmClient / secretsManagerClient /
env / localParameters), fetches the raw value, applies the fallback when the
provider returns nothing, runs the parser (throwing ParameterParsingError,
code err_parameter_parse, on failure), then runs the validator (throwing
ParameterValidationError, code err_parameter_validate, on failure).
Key resolution and aliases. An explicit parameter.alias wins; otherwise the
parameter name is looked up in the aliases map (commonly { ...process.env }).
This enables indirection such as BUCKET_ARN_SSM_PATH -> the actual SSM path,
so deployment config can point at parameters without code changes.
- Resolve configuration from multiple source:
- AWS SSM parameter store.
- AWS Secrets Manager.
- Local memory.
- Structured logging with Pino via mlabs-logger.
- Cache parameter values with cache-manager.
- Parameter key aliases (see usage below).
ace is a shared infrastructure utility, not a pipeline stage. It is published
to npm and imported by other PureSkill.gg Node backend services (e.g. glhf,
oauthjs, and the lambdas behind demo/replay/match processing and automatch) so
they can load their runtime config and secrets — bucket ARNs, API keys,
Steam/FACEIT credentials, polling intervals such as automatch min_interval, and
so on — from AWS at boot. It produces no domain data of its own; it sits
underneath nearly every Node service as the config-resolution layer.
It owns no cloud infrastructure. There is no serverless.yml, no Terraform, and
no CDK in this repo. At runtime it only reads from two AWS services via AWS
SDK v3 clients, using resource names that the consuming application supplies at
call time.
| Export | Source | Role |
|---|---|---|
getConfig |
lib/get-config.js |
Async. Resolves a map of named Parameters in parallel (cached + logged) and returns an object of resolved values keyed by caller name. |
Parameter |
lib/parameter.js |
Core abstraction wrapping a provider with fallback, parser, validator, and isSensitive. Lazily instantiates its provider, fetches, parses, and validates. Throws ParameterValidationError / ParameterParsingError. |
Each factory wires a provider plus an appropriate validator/parser. By convention
parameters are referenced by the caller's camelCase object key; secret-bearing
helpers set isSensitive: true so values are redacted in logs.
| Factory | Provider | Validation / parsing |
|---|---|---|
ssmString(name, fallback) |
SsmProvider |
non-empty string |
ssmNonNegativeInt(name, fallback) |
SsmProvider |
Number(v), must be a non-negative integer |
secretsManagerString(name, fallback) |
SecretsManagerProvider |
non-empty string, sensitive |
secretsManagerJson(name, fallback) |
SecretsManagerProvider |
JSON.parsed, sensitive |
envString(name, fallback) |
EnvProvider |
non-empty string from process.env (sets alias == name) |
localString(name, fallback) |
LocalProvider |
non-empty string from the in-memory localParameters object |
localNonNegativeInt(name, fallback) |
LocalProvider |
Number(v), must be a non-negative integer |
ace hardcodes no literal ARNs or parameter names — it never owns a resource. The names below are supplied by the consuming app at call time:
- SSM Parameter Store — read via
GetParameterCommand. TheNamecomes fromssmString/ssmNonNegativeInt, optionally indirected through an env-var alias. A missing parameter resolves toundefined. - Secrets Manager — read via
GetSecretValueCommand. TheSecretIdcomes fromsecretsManagerString/secretsManagerJson. Values are flagged sensitive and redacted in logs. A missing secret resolves toundefined.
ace deploys nothing, so it has no CloudWatch log group, DLQ, Sentry project, or Step Functions state of its own. All of its output appears in the logs of the host service that imports it.
- Normal logs: ace logs through the Pino logger passed in as
log(or a default @pureskillgg/mlabs-logger logger). Each parameter resolution emits a child-logger line tagged withparamName,paramAlias,paramKey, andparamProvider. Visibility depends entirely on the host'sLOG_LEVEL— per-parameter detail (including the redacted[Redacted]value previews) is atdebug. - Error logs: failures are plain JS exceptions, not AWS-native failure
channels. Each fetch's
try/catchlogslog.error({ err }, 'fail')and then rethrows;getConfigruns the fetches underPromise.all, so any rejection (e.g. an SSM/Secrets ManagerAccessDeniedor throttling error, or aParameterValidationError/ParameterParsingError) rejects the wholegetConfig. OnlyParameterNotFound(SSM) andResourceNotFoundException(Secrets Manager) are swallowed toundefined. - Where to look: in the CloudWatch log group of the consuming lambda/service (config typically resolves at boot, so look at the start of an invocation), or in CI output when a build runs the consumer. There is no ace-specific log group to search.
Get configuration from AWS SSM Parameter Store and AWS Secrets Manager.
import { ssmString, secretsManagerString, getConfig } from '@pureskillgg/ace'
const parameters = {
bucketArn: ssmString('/app/bucket_arn'),
apiKey: secretsManagerString('/app/api_key')
}
const { bucketArn, apiKey } = await getConfig({ parameters })import { SSMClient } from '@aws-sdk/client-ssm'
import { SecretsManagerClient } from '@aws-sdk/client-secrets-manager'
import cacheManager from 'cache-manager'
import { localString, ssmString, secretsManagerString, getConfig } from '@pureskillgg/ace'
process.env.BUCKET_ARN_SSM_PATH = '/app/bucket_arn'
process.env.API_KEY_SECRET_ID = '/app/api_key'
process.env.API_ORIGIN = 'https://example.com'
process.env.FOO = 'bar'
const parameters = {
bucketArn: ssmString('BUCKET_ARN'),
apiKey: secretsManagerString('API_KEY'),
apiOrigin: envString('API_ORIGIN'),
name: localString('FOO')
}
const localParameters = {
bar: 'baz'
}
const cache = cacheManager.caching()
const { bucketId, apiKey, apiOrigin } = await getConfig({
parameters,
localParameters,
aliases: { ...process.env },
ssmClient: new SSMClient(),
secretsManagerClient: new SecretsManagerClient(),
log: createLogger(),
cache
})Add this as a dependency to your project using npm with
$ npm install @pureskillgg/makenew-jsmodule
$ git clone https://github.com/pureskillgg/ace.git
$ cd ace
$ nvm install
$ npm install
Run the command below in a separate terminal window:
$ npm run test:watch
Primary development tasks are defined under scripts in package.json
and available via npm run.
View them with
$ npm run
The source code is hosted on GitHub. Clone the project with
$ git clone git@github.com:pureskillgg/ace.git
You will need Node.js with npm and a Node.js debugging client.
Be sure that all commands run under the correct Node version, e.g., if using nvm, install the correct version with
$ nvm install
Set the active version for each shell session with
$ nvm use
Install the development dependencies with
$ npm install
Use the npm version command to release a new version.
This will push a new git tag which will trigger a GitHub action.
Publishing may be triggered using on the web using a workflow_dispatch on GitHub Actions.
GitHub Actions should already be configured: this section is for reference only.
The following repository secrets must be set on GitHub Actions:
NPM_TOKEN: npm token for publishing packages.
These must be set manually.
The docs, version, and format GitHub actions require a user with write access to the repository including access to read and write packages. Set these additional secrets to enable the action:
GH_USER: The GitHub user's username.GH_TOKEN: A personal access token for the user.GIT_USER_NAME: The GitHub user's real name.GIT_USER_EMAIL: The GitHub user's email.GPG_PRIVATE_KEY: The GitHub user's GPG private key.GPG_PASSPHRASE: The GitHub user's GPG passphrase.
Please submit and comment on bug reports and feature requests.
To submit a patch:
- Fork it (https://github.com/pureskillgg/ace/fork).
- Create your feature branch (
git checkout -b my-new-feature). - Make changes.
- Commit your changes (
git commit -am 'Add some feature'). - Push to the branch (
git push origin my-new-feature). - Create a new Pull Request.
This npm package is licensed under the MIT license.
This software is provided by the copyright holders and contributors "as is" and any express or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall the copyright holder or contributors be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage.
