Mirror of https://github.com/roostorg/coop
github.com/roostorg/coop
1/**
2 * @fileoverview For now, we define correlation ids as hierarchical strings,
3 * with two parts: a type (which can be the event type that triggered the full
4 * execution flow that we're trying to correlate/log) and an id (which must be
5 * unique within the type). The functions in this file generate and parse these
6 * hierarchical strings, and return "branded" strings for type safety, using
7 * opaque types from type-fest.
8 */
9import { type Opaque } from 'type-fest';
10
11export type CorrelationId<Type extends string> = Opaque<Type, 'CorrelationId'>;
12
13export type CorrelationIdType<T extends CorrelationId<string>> =
14 T extends CorrelationId<infer U> ? U : never;
15
16/**
17 * @param source The identity of the flow that's being traced.
18 */
19export function toCorrelationId<Type extends string>(source: {
20 type: Type;
21 id: string;
22}) {
23 return `${source.type}:${source.id}` as CorrelationId<Type>;
24}
25
26export function fromCorrelationId<Type extends string>(
27 it: CorrelationId<Type>,
28) {
29 return it as unknown as string;
30}
31
32/**
33 * The correlation ids returned by {@see toCorrelationId} are heirarchical;
34 * i.e., they encode the type of event that triggered the flow, and an id for
35 * that event (which must be unique only within that event type).
36 * Normally, we want to use/store this full hierarchical id everywhere, even
37 * where the event type might be obvious from the context. Sometimes, though,
38 * we store the id without the prefix (e.g., in postgres, where the prefix would
39 * make the id inconsistent with our other primary keys), so this helper function
40 * can remove the prefix from the full id to let us do an equality comparison.
41 */
42export function getSourceId(it: CorrelationId<string>) {
43 return fromCorrelationId(it).split(':')[1];
44}
45
46export function getSourceType<T extends string>(it: CorrelationId<T>): T {
47 return fromCorrelationId(it).split(':')[0] as T;
48}