@myvitalrx/runtime-metadata
v1.0.3
Published
Runtime metadata consumption SDK — S3 projection download, cache, and O(1) resolve for domain services
Readme
@myvitalrx/runtime-metadata
Runtime Metadata Consumption SDK — downloads projection JSON from S3 via
current.json, caches it in memory, and exposes O(1) resolve(typeCode, valueCode)
for every domain service.
Metadata is one Read Model on the platform Read Model Cache. Future Localization / Country / Organization / Theme runtimes plug into the same cache / downloader / provider contracts without redesigning this library.
Install
pnpm add @myvitalrx/runtime-metadata @myvitalrx/platform-tools@myvitalrx/platform-tools is a peer dependency (required for structured
logging via @myvitalrx/platform-tools/observability). Projection types,
path helpers, and error bases are bundled — you do not install
@api-hub/metadata-projection or @api-hub/utils separately.
Architecture
Publisher
→ {MetadataTypeCode}.json (+ common.json + relationship-index.json + manifest.json + current.json)
Runtime:
current.json / manifest.json
↓
validate release (schema, checksums, lookupIndex)
↓
MetadataCache bootstrap (manifest)
↓
Response DTO → collect MetadataTypeCodes
↓
Download only required {MetadataTypeCode}.json
↓
Merge cache (keys = MetadataTypeCode)
↓
MetadataResolver → ResponseProjector
getRelatedValues / getRelatedMetadata → relationship-index.json (+ target projection)Manifest role: release validation, revision checking, integrity (files),
lookupIndex for resolve. Not used for projection file discovery.
Usage
Domain and runtime services do not construct S3Client or pass the
projections bucket. This package creates the S3 client and names storage from
stage ({STAGE}-mvx-metadata-projections-bucket, prefix metadata-projections).
import { getRuntimeMetadataService } from '@myvitalrx/runtime-metadata';
const metadata = getRuntimeMetadataService();
await metadata.initialize();
// After DTOs arrive (or via MetadataResponseProjector):
await metadata.ensureProjectionsForResponse(responseDto);
const condition = metadata.resolve('Condition', 'ASTHMA');
const metricV1 = metadata.resolve('MetricCode', 'BP_SYSTOLIC', 1);
metadata.supportsType('MetricCode');
metadata.listMetadataTypes();
metadata.getManifest();
metadata.getLookupIndex();
// On MetadataProjectionCompleted.v1 — reload bootstrap via current.json
await metadata.onProjectionCompleted(payload.releaseId);
const health = metadata.getHealth();createRuntimeMetadataFromEnv() and new RuntimeMetadataService() with no
arguments do the same S3 setup. Inject client only in unit tests.
Storage names this package owns
| Setting | Default |
|---|---|
| Bucket | {STAGE}-mvx-metadata-projections-bucket |
| Prefix | metadata-projections |
| Environment | PROJECTION_ENVIRONMENT / STAGE / NODE_ENV / dev |
| Region | AWS_REGION / REGION |
Public projection API
RuntimeMetadataService also exposes lifecycle and query helpers:
| Method | Description |
|---|---|
| initialize(revision?) | Bootstrap via current.json → manifest |
| load(typeCodes?) | Bootstrap only, or selective domain file download |
| refresh(revision?) | Check current.json and reload when changed |
| refreshType(typeCode) | Re-download one {typeCode}.json |
| getMetadataType(typeCode) | Manifest catalog entry |
| getMetadataTypes() | All manifest catalog entries |
| getMetadataValue(...) | Same as resolve |
| getMetadataValues(typeCode) | Same as getAll |
| getMetadataAttributeSchemas(typeCode?) | Merged value attributes maps |
| getRelationshipIndex() | Load relationship-index.json for the active release |
| getRelated(typeCode, valueCode) | Nested map of related types → codes (undefined if source missing) |
| getRelatedValues(sourceType, sourceValue, targetType) | Stable string[] of related codes ([] when none) |
| getRelatedMetadata(sourceType, sourceValue, targetType) | Hydrated ProjectionEntry[] from the target projection file |
| clearCache() | Clear this library's projection cache only |
Boundaries
This library does:
- Create the S3 client and resolve storage names (bucket, prefix, environment, region)
- Resolve the active release via
current.json(never list S3 for “latest”) - Download + validate
manifest.jsonfor release/integrity/lookupIndex - Bootstrap with
common.jsononly; download domain files by MetadataTypeCode on demand - Build an immutable in-memory cache with atomic replacement (and selective merge)
- Expose generic resolver APIs:
resolve(typeCode, valueCode),supportsType,listMetadataTypes,getManifest,getLookupIndex,getRelationshipIndex,getRelated,getRelatedValues,getRelatedMetadata - Refresh bootstrap on startup, projection-completed events, and optional periodic checks
- Report health (release id, cache age, refresh status)
This library does not:
- Require domain or runtime services to pass an S3 client, bucket, or prefix
- Invent retry policies (AWS SDK client retries apply)
- Publish events or own EventBridge consumers (call
onProjectionCompleted()) - Own HTTP response field names (convention / DTO bindings live in the projector layer)
- Discover projection filenames from the manifest (filename =
{MetadataTypeCode}.json)
Monorepo build
nx build runtime-metadata metadata-projection utils
nx build runtime-metadata-package
# or
pnpm run build:runtime-metadataPublish to npm
Publish this package (packages/runtime-metadata), never libs/runtime-metadata.
The npm tarball must include dist/index.js (the bundled SDK). 1.0.0 / 1.0.1
were empty because the workspace lib was published without compiled output.
pnpm run build:runtime-metadata
pnpm run publish:runtime-metadata # from repo root — builds, verifies dist, then publishesDeep architecture notes live in libs/runtime-metadata/README.md.
Generic relationship lookup
relationship-index.json is loaded through the same current.json → manifest.json
release path as domain projections. Consumers never pass release IDs or S3 keys.
const codes = await metadata.getRelatedValues('Category', 'CHRONIC', 'Condition');
// ['DIABETES', 'HYPERTENSION']
const reverse = await metadata.getRelatedValues('Condition', 'DIABETES', 'Category');
// ['CHRONIC']
const records = await metadata.getRelatedMetadata('Category', 'CHRONIC', 'Condition');These APIs are metadata-type agnostic. Category → Condition is only an example.
Missing source, missing target type, and empty relationships return [].
relationType is not part of the runtime lookup identity — the published index
collapses edges between the same type/value pair.
Live S3 inspection of a deployed relationship-index.json is environment/IAM
dependent and is not required to trust the local release tests.
