/** * AWS SSM Parameter Store backend for env-config documents. * * Layout: * /log10x/env-config/{env_id} → JSON-serialised EnvironmentConfig * * One parameter per environment. The id under the `/log10x/env-config/` * prefix is the canonical `env_id` (UUID); nickname lookups are resolved by * listing the prefix and matching the parsed document's `nickname` field. * * Parameter type is `String` today. Promoting to `SecureString` is a one-line * change once customers wire a KMS key — see the `kmsKeyId` option on * `PutParameter`. We avoid SecureString by default so callers without a * configured KMS key still get a working store. * * Availability is reported defensively: * - if `@aws-sdk/client-ssm` is not installed at all we return * `{ available: false, reason: ... }` with a clear hint, never throw. * This lets the resolver fall through to the next store (k8s ConfigMap, * local file) on a stripped-down install. * - if no AWS region is resolvable (no AWS_REGION / AWS_DEFAULT_REGION and * no constructor arg) we report unavailable rather than letting the SDK * throw at first call. * - if credentials don't resolve via the default provider chain we report * unavailable; the resolver moves on. * * Throwing is reserved for "the store IS available, but this op failed" — * malformed JSON in a parameter value, a parameter not found mid-write, etc. */ import type { EnvConfigStore, StoreKind } from './store-interface.js'; import { type EnvironmentConfig } from './types.js'; /** * Constructor options. All optional — defaults read from AWS_REGION / * AWS_DEFAULT_REGION and the default credential provider chain. */ export interface AwsSsmStoreOptions { /** AWS region. Falls back to AWS_REGION / AWS_DEFAULT_REGION. */ region?: string; /** * Optional KMS key id/arn/alias. When set we promote the parameter type * to `SecureString` on write so SSM encrypts at rest with the named key. * When unset we write plain `String` parameters. */ kmsKeyId?: string; /** * Override the prefix. Defaults to `/log10x/env-config/`. Trailing slash * is normalised either way. */ prefix?: string; } export declare class AwsSsmStore implements EnvConfigStore { readonly kind: StoreKind; private readonly region; private readonly kmsKeyId; private readonly prefix; private sdkPromise; private clientPromise; constructor(opts?: AwsSsmStoreOptions); /** Lazy import wrapper; cached so we only pay the import cost once. */ private loadSdk; /** Lazy client; one per store instance. */ private getClient; /** * Soft reachability check. Never throws. * * Order of checks (cheapest first): * 1. SDK is importable * 2. region is resolvable * 3. credentials resolve via the default provider chain */ isAvailable(): Promise<{ available: boolean; reason: string; }>; /** * Resolve a single document by env_id or nickname. Tries direct GetParameter * first (cheap when caller passes env_id), then falls back to a list+match * scan for nicknames. */ read(envIdOrNickname: string): Promise; write(config: EnvironmentConfig): Promise; list(): Promise; delete(envId: string): Promise; /** * Single GetParameter wrapped to return null on ParameterNotFound rather * than throwing. WithDecryption: true so SecureString upgrades work * transparently. */ private getParameter; }