Skip to main content

Recipes

Building route metadata for a custom decorator

This is the pattern @quik/http's route decorators use internally (packages/http/src/router/decorators/Metadata.ts):

import { MetadataStore } from '@quik/metadata';

type RouteMeta = {
name: string;
flags: string[];
};

function getRouteMetadata(context: ClassDecoratorContext): RouteMeta {
const metadata = MetadataStore.get<RouteMeta>(context.metadata);

if (context.name && !metadata.name) {
metadata.name = context.name.toString();
}
if (!metadata.flags) {
metadata.flags = [];
}

return metadata;
}

Because MetadataStore.get lazily creates an empty object on first access, decorator implementations can call it repeatedly across multiple decorators applied to the same class/method and accumulate fields on the same record.

Inspecting all registered metadata

import { MetadataStore } from '@quik/metadata';

const entries = MetadataStore.snapshot(); // Array<Record<string, unknown>>

snapshot() is memoized between writes — it only recomputes the array after register/get adds a new key or clear() runs, so repeated calls are cheap.

Clearing metadata on bootstrap reset

@quik/metadata's onReset() hook calls MetadataStore.clear() automatically during a full bootstrap restart. clear() empties the snapshot()-backing cache (and invalidates the memoized snapshot array) — it does not, and cannot, remove entries from the underlying WeakMap, since WeakMap has no way to enumerate or bulk-clear its keys. Existing get(metadata) lookups for a DecoratorMetadata key already seen will still return the same object after clear().