@equipe-tech/observability 0.2.1 → 0.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -9
- package/dist/BrowserEvents.d.ts +89 -12
- package/dist/BrowserEvents.js +67 -13
- package/dist/Correlation.d.ts +51 -0
- package/dist/Correlation.js +95 -0
- package/dist/Metrics.d.ts +19 -3
- package/dist/Metrics.js +16 -0
- package/dist/MetricsRuntime.d.ts +45 -3
- package/dist/MetricsRuntime.js +478 -120
- package/dist/PolicyOtlpLogger.d.ts +18 -0
- package/dist/PolicyOtlpLogger.js +142 -0
- package/dist/RedactionPolicy.d.ts +2 -9
- package/dist/RedactionPolicy.js +2 -246
- package/dist/ResourceIdentity.d.ts +47 -0
- package/dist/ResourceIdentity.js +82 -0
- package/dist/Telemetry.d.ts +18 -3
- package/dist/Telemetry.js +43 -25
- package/dist/TelemetryConfig.d.ts +11 -4
- package/dist/TelemetryConfig.js +38 -10
- package/dist/audit/AuditCommitDocument.d.ts +41 -0
- package/dist/audit/AuditCommitDocument.js +58 -0
- package/dist/audit/AuditDigest.d.ts +11 -0
- package/dist/audit/AuditDigest.js +25 -0
- package/dist/audit/AuditOutbox.d.ts +75 -0
- package/dist/audit/AuditOutbox.js +104 -0
- package/dist/audit/AuditPublisher.d.ts +49 -0
- package/dist/audit/AuditPublisher.js +60 -0
- package/dist/audit/AuditRecord.d.ts +128 -0
- package/dist/audit/AuditRecord.js +172 -0
- package/dist/audit/CommittedAuditRecordInternal.d.ts +11 -0
- package/dist/audit/CommittedAuditRecordInternal.js +13 -0
- package/dist/audit/InvalidAuditRecord.d.ts +12 -0
- package/dist/audit/InvalidAuditRecord.js +16 -0
- package/dist/audit/index.d.ts +7 -0
- package/dist/audit/index.js +7 -0
- package/dist/browser/BrowserClient.d.ts +82 -3
- package/dist/browser/BrowserClient.js +322 -28
- package/dist/browser/BrowserEventLimits.d.ts +8 -0
- package/dist/browser/BrowserEventLimits.js +8 -0
- package/dist/browser/BrowserMetricRecorder.d.ts +17 -0
- package/dist/browser/BrowserMetricRecorder.js +35 -0
- package/dist/browser/BrowserTelemetry.d.ts +40 -0
- package/dist/browser/BrowserTelemetry.js +105 -0
- package/dist/browser/ClientPolicy.d.ts +3 -0
- package/dist/browser/ClientPolicy.js +52 -0
- package/dist/browser/client.d.ts +3 -2
- package/dist/browser/client.js +2 -1
- package/dist/browser/index.d.ts +4 -37
- package/dist/browser/index.js +3 -95
- package/dist/contract/ContractCompatibility.d.ts +31 -0
- package/dist/contract/ContractCompatibility.js +274 -0
- package/dist/contract/ContractIndex.d.ts +54 -0
- package/dist/contract/ContractIndex.js +178 -0
- package/dist/contract/ContractSurface.d.ts +111 -0
- package/dist/contract/ContractSurface.js +116 -0
- package/dist/contract/EventName.d.ts +6 -0
- package/dist/contract/EventName.js +55 -0
- package/dist/contract/EventProducer.d.ts +123 -0
- package/dist/contract/EventProducer.js +209 -0
- package/dist/contract/MetricContractError.d.ts +19 -0
- package/dist/contract/MetricContractError.js +19 -0
- package/dist/contract/MetricDefinition.d.ts +61 -0
- package/dist/contract/MetricDefinition.js +91 -0
- package/dist/contract/MetricProducer.d.ts +42 -0
- package/dist/contract/MetricProducer.js +123 -0
- package/dist/contract/OrganizationEvents.d.ts +165 -0
- package/dist/contract/OrganizationEvents.js +97 -0
- package/dist/contract/TelemetryContract.d.ts +95 -0
- package/dist/contract/TelemetryContract.js +451 -0
- package/dist/contract/TelemetryContractError.d.ts +44 -0
- package/dist/contract/TelemetryContractError.js +64 -0
- package/dist/contract/TelemetryEvent.d.ts +59 -0
- package/dist/contract/TelemetryEvent.js +54 -0
- package/dist/contract/index.d.ts +11 -0
- package/dist/contract/index.js +11 -0
- package/dist/effect/WideEvent.d.ts +3 -0
- package/dist/effect/WideEvent.js +20 -0
- package/dist/effect/WideEventSink.d.ts +3 -0
- package/dist/effect/WideEventSink.js +79 -0
- package/dist/effect/index.d.ts +2 -0
- package/dist/effect/index.js +2 -0
- package/dist/index.d.ts +17 -2
- package/dist/index.js +11 -2
- package/dist/metrics/InstrumentGrammar.d.ts +5 -0
- package/dist/metrics/InstrumentGrammar.js +12 -0
- package/dist/metrics/MetricScalar.d.ts +3 -0
- package/dist/metrics/MetricScalar.js +5 -0
- package/dist/node/AuditDigest.d.ts +3 -0
- package/dist/node/AuditDigest.js +6 -0
- package/dist/node/BrowserEventIngest.d.ts +7 -2
- package/dist/node/BrowserEventIngest.js +111 -19
- package/dist/node/LocalCollector.d.ts +20 -0
- package/dist/node/LocalCollector.js +188 -0
- package/dist/node/Observability.d.ts +49 -0
- package/dist/node/Observability.js +190 -0
- package/dist/node/Runtime.d.ts +4 -1
- package/dist/node/index.d.ts +4 -0
- package/dist/node/index.js +3 -0
- package/dist/policy/BrowserFieldPolicy.d.ts +7 -0
- package/dist/policy/BrowserFieldPolicy.js +298 -0
- package/dist/policy/DataPolicy.d.ts +19 -0
- package/dist/policy/DataPolicy.js +254 -0
- package/dist/policy/DataPolicyError.d.ts +22 -0
- package/dist/policy/DataPolicyError.js +25 -0
- package/dist/policy/Deduplication.d.ts +13 -0
- package/dist/policy/Deduplication.js +44 -0
- package/dist/policy/DefectEnvelope.d.ts +25 -0
- package/dist/policy/DefectEnvelope.js +52 -0
- package/dist/policy/MetricLabelPolicy.d.ts +5 -0
- package/dist/policy/MetricLabelPolicy.js +65 -0
- package/dist/policy/PolicyTransform.d.ts +16 -0
- package/dist/policy/PolicyTransform.js +136 -0
- package/dist/policy/PolicyVocabulary.d.ts +10 -0
- package/dist/policy/PolicyVocabulary.js +84 -0
- package/dist/policy/ResourceAttributePolicy.d.ts +9 -0
- package/dist/policy/ResourceAttributePolicy.js +33 -0
- package/dist/policy/entrypoint.d.ts +2 -0
- package/dist/policy/entrypoint.js +2 -0
- package/dist/policy/index.d.ts +17 -0
- package/dist/policy/index.js +9 -0
- package/dist/profile/DataPolicy.d.ts +2 -0
- package/dist/profile/DataPolicy.js +1 -0
- package/dist/profile/EnvironmentPolicy.d.ts +22 -0
- package/dist/profile/EnvironmentPolicy.js +41 -0
- package/dist/profile/LifecycleRegistry.d.ts +24 -0
- package/dist/profile/LifecycleRegistry.js +240 -0
- package/dist/profile/ObservabilityAdapter.d.ts +115 -0
- package/dist/profile/ObservabilityAdapter.js +50 -0
- package/dist/profile/ObservabilityConfig.d.ts +68 -0
- package/dist/profile/ObservabilityConfig.js +125 -0
- package/dist/profile/ObservabilityConfigError.d.ts +23 -0
- package/dist/profile/ObservabilityConfigError.js +39 -0
- package/dist/profile/ObservabilityProfile.d.ts +49 -0
- package/dist/profile/ObservabilityProfile.js +121 -0
- package/dist/profile/ReactWebProfile.d.ts +8 -0
- package/dist/profile/ReactWebProfile.js +7 -0
- package/dist/profile/index.d.ts +5 -0
- package/dist/profile/index.js +5 -0
- package/dist/testing/conformance/ConformanceAssertions.d.ts +5 -0
- package/dist/testing/conformance/ConformanceAssertions.js +31 -0
- package/dist/testing/conformance/ConformanceFailure.d.ts +35 -0
- package/dist/testing/conformance/ConformanceFailure.js +56 -0
- package/dist/testing/conformance/ConformanceModel.d.ts +97 -0
- package/dist/testing/conformance/ConformanceModel.js +8 -0
- package/dist/testing/conformance/ConformanceRegistry.d.ts +13 -0
- package/dist/testing/conformance/ConformanceRegistry.js +190 -0
- package/dist/testing/conformance/ConformanceRunner.d.ts +5 -0
- package/dist/testing/conformance/ConformanceRunner.js +198 -0
- package/dist/testing/conformance/TelemetryEvidence.d.ts +91 -0
- package/dist/testing/conformance/TelemetryEvidence.js +370 -0
- package/dist/testing/conformance/index.d.ts +10 -0
- package/dist/testing/conformance/index.js +6 -0
- package/dist/testing/contract.d.ts +81 -0
- package/dist/testing/contract.js +93 -0
- package/dist/testing/deployedCanary.d.ts +1 -0
- package/dist/testing/deployedCanary.js +1 -0
- package/dist/testing/index.d.ts +40 -3
- package/dist/testing/index.js +122 -5
- package/dist/trace/HttpServerOtlpTracer.d.ts +42 -0
- package/dist/trace/HttpServerOtlpTracer.js +301 -0
- package/package.json +16 -29
- package/dist/WideEvent.d.ts +0 -5
- package/dist/WideEvent.js +0 -6
- package/dist/nestjs/BrowserEventsController.d.ts +0 -21
- package/dist/nestjs/BrowserEventsController.js +0 -52
- package/dist/nestjs/HttpRoutePolicy.d.ts +0 -23
- package/dist/nestjs/HttpRoutePolicy.js +0 -179
- package/dist/nestjs/HttpServerOtlpTracer.d.ts +0 -15
- package/dist/nestjs/HttpServerOtlpTracer.js +0 -154
- package/dist/nestjs/RequestWideEventTraceCorrelation.d.ts +0 -15
- package/dist/nestjs/RequestWideEventTraceCorrelation.js +0 -13
- package/dist/nestjs/TelemetryInterceptor.d.ts +0 -31
- package/dist/nestjs/TelemetryInterceptor.js +0 -268
- package/dist/nestjs/TelemetryModule.d.ts +0 -53
- package/dist/nestjs/TelemetryModule.js +0 -428
- package/dist/nestjs/index.d.ts +0 -5
- package/dist/nestjs/index.js +0 -4
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { AttributeClassification, TelemetryContract, TelemetryContractInput } from "./TelemetryContract.js";
|
|
2
|
+
import type { EventKind } from "./TelemetryEvent.js";
|
|
3
|
+
import type { MetricKind } from "./MetricDefinition.js";
|
|
4
|
+
export type ContractIndexEventAttribute = {
|
|
5
|
+
readonly name: string;
|
|
6
|
+
readonly classification: AttributeClassification;
|
|
7
|
+
};
|
|
8
|
+
export type ContractIndexEvent = {
|
|
9
|
+
readonly name: string;
|
|
10
|
+
readonly kind: EventKind;
|
|
11
|
+
readonly attributes: ReadonlyArray<string>;
|
|
12
|
+
readonly attributeClassifications: ReadonlyArray<ContractIndexEventAttribute>;
|
|
13
|
+
};
|
|
14
|
+
export type ContractIndexMetric = {
|
|
15
|
+
readonly name: string;
|
|
16
|
+
readonly kind: MetricKind;
|
|
17
|
+
readonly unit: string;
|
|
18
|
+
readonly attributes: ReadonlyArray<string>;
|
|
19
|
+
};
|
|
20
|
+
export type ContractSignalReference = {
|
|
21
|
+
readonly kind: "event" | "metric";
|
|
22
|
+
readonly name: string;
|
|
23
|
+
};
|
|
24
|
+
export type ContractSignalAliasDefinition = {
|
|
25
|
+
readonly source: ContractSignalReference;
|
|
26
|
+
readonly target: ContractSignalReference;
|
|
27
|
+
readonly since: string;
|
|
28
|
+
};
|
|
29
|
+
export type ContractSignalAliasMetadata = {
|
|
30
|
+
readonly version: 1;
|
|
31
|
+
readonly aliases: ReadonlyArray<ContractSignalAliasDefinition>;
|
|
32
|
+
};
|
|
33
|
+
export type ContractSignalAlias = {
|
|
34
|
+
readonly kind: "event" | "metric";
|
|
35
|
+
readonly from: string;
|
|
36
|
+
readonly to: string;
|
|
37
|
+
};
|
|
38
|
+
export type ContractIndex = {
|
|
39
|
+
readonly index: 1;
|
|
40
|
+
readonly contractVersion: number;
|
|
41
|
+
readonly service: string;
|
|
42
|
+
readonly events: ReadonlyArray<ContractIndexEvent>;
|
|
43
|
+
readonly metrics: ReadonlyArray<ContractIndexMetric>;
|
|
44
|
+
readonly aliases: ReadonlyArray<ContractSignalAlias>;
|
|
45
|
+
};
|
|
46
|
+
export declare const maximumContractAliasCount = 4096;
|
|
47
|
+
export declare const maximumContractAliasDepth = 128;
|
|
48
|
+
export declare const maximumContractAliasTargets = 256;
|
|
49
|
+
export declare class ContractIndexAliasError extends Error {
|
|
50
|
+
readonly code: "OBS_CONTRACT_ALIAS_COUNT_EXCEEDED" | "OBS_CONTRACT_ALIAS_DEPTH_EXCEEDED" | "OBS_CONTRACT_ALIAS_TARGETS_EXCEEDED" | "OBS_CONTRACT_ALIAS_CYCLE";
|
|
51
|
+
readonly name = "ContractIndexAliasError";
|
|
52
|
+
constructor(code: "OBS_CONTRACT_ALIAS_COUNT_EXCEEDED" | "OBS_CONTRACT_ALIAS_DEPTH_EXCEEDED" | "OBS_CONTRACT_ALIAS_TARGETS_EXCEEDED" | "OBS_CONTRACT_ALIAS_CYCLE", message: string);
|
|
53
|
+
}
|
|
54
|
+
export declare const contractIndex: <Definition extends TelemetryContractInput>(contract: TelemetryContract<Definition>, service: string, aliasMetadata?: ContractSignalAliasMetadata) => ContractIndex;
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
export const maximumContractAliasCount = 4_096;
|
|
2
|
+
export const maximumContractAliasDepth = 128;
|
|
3
|
+
export const maximumContractAliasTargets = 256;
|
|
4
|
+
export class ContractIndexAliasError extends Error {
|
|
5
|
+
code;
|
|
6
|
+
name = "ContractIndexAliasError";
|
|
7
|
+
constructor(code, message) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.code = code;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
const byName = (left, right) => left.name.localeCompare(right.name);
|
|
13
|
+
const signalNamePattern = /^[a-z][a-z0-9_]*(?:[.][a-z][a-z0-9_]*)+$/;
|
|
14
|
+
const isoDatePattern = /^\d{4}-\d{2}-\d{2}$/;
|
|
15
|
+
const isIsoDate = (value) => {
|
|
16
|
+
if (!isoDatePattern.test(value))
|
|
17
|
+
return false;
|
|
18
|
+
const timestamp = Date.parse(`${value}T00:00:00.000Z`);
|
|
19
|
+
return Number.isFinite(timestamp) && new Date(timestamp).toISOString().slice(0, 10) === value;
|
|
20
|
+
};
|
|
21
|
+
const aliasKey = (kind, name) => `${kind}\u0000${name}`;
|
|
22
|
+
const buildAliasGraph = (aliases) => {
|
|
23
|
+
if (aliases.length > maximumContractAliasCount) {
|
|
24
|
+
throw new ContractIndexAliasError("OBS_CONTRACT_ALIAS_COUNT_EXCEEDED", `Contract aliases exceed the maximum count of ${maximumContractAliasCount}.`);
|
|
25
|
+
}
|
|
26
|
+
const adjacency = new Map();
|
|
27
|
+
for (const alias of aliases) {
|
|
28
|
+
const key = aliasKey(alias.kind, alias.from);
|
|
29
|
+
const targets = adjacency.get(key) ?? new Set();
|
|
30
|
+
targets.add(alias.to);
|
|
31
|
+
adjacency.set(key, targets);
|
|
32
|
+
}
|
|
33
|
+
const colors = new Map();
|
|
34
|
+
const depths = new Map();
|
|
35
|
+
const depth = (kind, source, traversed) => {
|
|
36
|
+
if (traversed > maximumContractAliasDepth) {
|
|
37
|
+
throw new ContractIndexAliasError("OBS_CONTRACT_ALIAS_DEPTH_EXCEEDED", `Contract alias depth exceeds the maximum of ${maximumContractAliasDepth}.`);
|
|
38
|
+
}
|
|
39
|
+
const key = aliasKey(kind, source);
|
|
40
|
+
const cached = depths.get(key);
|
|
41
|
+
if (cached !== undefined)
|
|
42
|
+
return cached;
|
|
43
|
+
if (colors.get(key) === "gray") {
|
|
44
|
+
throw new ContractIndexAliasError("OBS_CONTRACT_ALIAS_CYCLE", "Contract aliases contain a cycle.");
|
|
45
|
+
}
|
|
46
|
+
colors.set(key, "gray");
|
|
47
|
+
let value = 0;
|
|
48
|
+
for (const target of adjacency.get(key) ?? []) {
|
|
49
|
+
value = Math.max(value, 1 + depth(kind, target, traversed + 1));
|
|
50
|
+
if (value > maximumContractAliasDepth) {
|
|
51
|
+
throw new ContractIndexAliasError("OBS_CONTRACT_ALIAS_DEPTH_EXCEEDED", `Contract alias depth exceeds the maximum of ${maximumContractAliasDepth}.`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
colors.set(key, "black");
|
|
55
|
+
depths.set(key, value);
|
|
56
|
+
return value;
|
|
57
|
+
};
|
|
58
|
+
for (const alias of aliases)
|
|
59
|
+
depth(alias.kind, alias.from, 0);
|
|
60
|
+
const expansions = new Map();
|
|
61
|
+
const expand = (kind, source) => {
|
|
62
|
+
const key = aliasKey(kind, source);
|
|
63
|
+
const cached = expansions.get(key);
|
|
64
|
+
if (cached !== undefined)
|
|
65
|
+
return cached;
|
|
66
|
+
const targets = new Set([source]);
|
|
67
|
+
for (const target of adjacency.get(key) ?? []) {
|
|
68
|
+
for (const nestedTarget of expand(kind, target)) {
|
|
69
|
+
targets.add(nestedTarget);
|
|
70
|
+
if (targets.size > maximumContractAliasTargets) {
|
|
71
|
+
throw new ContractIndexAliasError("OBS_CONTRACT_ALIAS_TARGETS_EXCEEDED", `Contract alias expansion exceeds the maximum of ${maximumContractAliasTargets} targets.`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
expansions.set(key, targets);
|
|
76
|
+
return targets;
|
|
77
|
+
};
|
|
78
|
+
return { expand };
|
|
79
|
+
};
|
|
80
|
+
const validatedAliases = (contract, metadata) => {
|
|
81
|
+
const eventEntries = [...contract.eventByName.values()];
|
|
82
|
+
const metricEntries = [...contract.metricByName.values()];
|
|
83
|
+
const events = new Map();
|
|
84
|
+
const metrics = new Map();
|
|
85
|
+
for (const event of eventEntries)
|
|
86
|
+
events.set(event.name, event);
|
|
87
|
+
for (const metric of metricEntries)
|
|
88
|
+
metrics.set(metric.name, metric);
|
|
89
|
+
if (metadata.aliases.length > maximumContractAliasCount) {
|
|
90
|
+
throw new ContractIndexAliasError("OBS_CONTRACT_ALIAS_COUNT_EXCEEDED", `Contract aliases exceed the maximum count of ${maximumContractAliasCount}.`);
|
|
91
|
+
}
|
|
92
|
+
const aliases = metadata.aliases.map((alias) => {
|
|
93
|
+
if (alias.source.kind !== alias.target.kind) {
|
|
94
|
+
throw new TypeError("Contract alias source and target kinds must match.");
|
|
95
|
+
}
|
|
96
|
+
if (!signalNamePattern.test(alias.source.name) || !signalNamePattern.test(alias.target.name)) {
|
|
97
|
+
throw new TypeError("Contract alias names must use the telemetry signal grammar.");
|
|
98
|
+
}
|
|
99
|
+
if (alias.source.name === alias.target.name) {
|
|
100
|
+
throw new TypeError("Contract alias source and target must differ.");
|
|
101
|
+
}
|
|
102
|
+
if (!isIsoDate(alias.since)) {
|
|
103
|
+
throw new TypeError("Contract alias since must be an ISO calendar date.");
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
kind: alias.source.kind,
|
|
107
|
+
from: alias.source.name,
|
|
108
|
+
to: alias.target.name,
|
|
109
|
+
};
|
|
110
|
+
});
|
|
111
|
+
const aliasGraph = buildAliasGraph(aliases);
|
|
112
|
+
for (const alias of aliases)
|
|
113
|
+
aliasGraph.expand(alias.kind, alias.from);
|
|
114
|
+
for (const alias of aliases) {
|
|
115
|
+
const targetExists = alias.kind === "event" ? events.has(alias.to) : metrics.has(alias.to);
|
|
116
|
+
if (!targetExists) {
|
|
117
|
+
throw new TypeError(`Contract alias target ${alias.to} is not declared.`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const metricSources = new Set(aliases.filter((alias) => alias.kind === "metric").map((alias) => alias.from));
|
|
121
|
+
for (const source of metricSources) {
|
|
122
|
+
const names = aliasGraph.expand("metric", source);
|
|
123
|
+
const targets = [...names].flatMap((name) => {
|
|
124
|
+
const metric = metrics.get(name);
|
|
125
|
+
return metric === undefined ? [] : [metric];
|
|
126
|
+
});
|
|
127
|
+
const first = targets[0];
|
|
128
|
+
if (first !== undefined &&
|
|
129
|
+
targets.some((target) => target.kind !== first.kind ||
|
|
130
|
+
target.unit !== first.unit ||
|
|
131
|
+
[...target.attributes.keys()].sort().join("\u0000") !==
|
|
132
|
+
[...first.attributes.keys()].sort().join("\u0000"))) {
|
|
133
|
+
throw new TypeError(`Contract metric alias source ${source} targets incompatible kind, unit, or attributes.`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const eventSources = new Set(aliases.filter((alias) => alias.kind === "event").map((alias) => alias.from));
|
|
137
|
+
for (const source of eventSources) {
|
|
138
|
+
const names = aliasGraph.expand("event", source);
|
|
139
|
+
const targets = [...names].flatMap((name) => {
|
|
140
|
+
const event = events.get(name);
|
|
141
|
+
return event === undefined ? [] : [event];
|
|
142
|
+
});
|
|
143
|
+
const first = targets[0];
|
|
144
|
+
const signature = (event) => [...event.attributes.entries()]
|
|
145
|
+
.map(([name, attribute]) => `${name}\u0000${attribute.classification}`)
|
|
146
|
+
.sort()
|
|
147
|
+
.join("\u0001");
|
|
148
|
+
if (first !== undefined &&
|
|
149
|
+
targets.some((target) => target.kind !== first.kind || signature(target) !== signature(first))) {
|
|
150
|
+
throw new TypeError(`Contract event alias source ${source} targets incompatible kind, attributes, or classifications.`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return aliases.sort((left, right) => `${left.kind}\u0000${left.from}\u0000${left.to}`.localeCompare(`${right.kind}\u0000${right.from}\u0000${right.to}`));
|
|
154
|
+
};
|
|
155
|
+
export const contractIndex = (contract, service, aliasMetadata = { version: 1, aliases: [] }) => ({
|
|
156
|
+
index: 1,
|
|
157
|
+
contractVersion: contract.version,
|
|
158
|
+
service,
|
|
159
|
+
events: [...contract.eventByName.values()]
|
|
160
|
+
.map((event) => ({
|
|
161
|
+
name: event.name,
|
|
162
|
+
kind: event.kind,
|
|
163
|
+
attributes: [...event.attributes.keys()].sort(),
|
|
164
|
+
attributeClassifications: [...event.attributes.entries()]
|
|
165
|
+
.map(([name, attribute]) => ({ name, classification: attribute.classification }))
|
|
166
|
+
.sort((left, right) => left.name.localeCompare(right.name)),
|
|
167
|
+
}))
|
|
168
|
+
.sort(byName),
|
|
169
|
+
metrics: [...contract.metricByName.values()]
|
|
170
|
+
.map((metric) => ({
|
|
171
|
+
name: metric.name,
|
|
172
|
+
kind: metric.kind,
|
|
173
|
+
unit: metric.unit,
|
|
174
|
+
attributes: [...metric.attributes.keys()].sort(),
|
|
175
|
+
}))
|
|
176
|
+
.sort(byName),
|
|
177
|
+
aliases: validatedAliases(contract, aliasMetadata),
|
|
178
|
+
});
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
import type { AuditOutcome } from "../audit/AuditRecord.js";
|
|
3
|
+
import type { AttributeClassification, TelemetryContract, TelemetryContractInput } from "./TelemetryContract.js";
|
|
4
|
+
import type { EventKind } from "./TelemetryEvent.js";
|
|
5
|
+
import type { MetricKind, MetricAttributeScalar } from "./MetricDefinition.js";
|
|
6
|
+
import type { ContractSignalAliasMetadata } from "./ContractIndex.js";
|
|
7
|
+
export type ContractSurfaceEventAttribute = {
|
|
8
|
+
readonly name: string;
|
|
9
|
+
readonly required: boolean;
|
|
10
|
+
readonly classification: AttributeClassification;
|
|
11
|
+
readonly metricLabel: boolean;
|
|
12
|
+
};
|
|
13
|
+
export type ContractSurfaceEvent = {
|
|
14
|
+
readonly name: string;
|
|
15
|
+
readonly kind: EventKind;
|
|
16
|
+
readonly outcomeMeaning: ReadonlyArray<string>;
|
|
17
|
+
readonly attributes: ReadonlyArray<ContractSurfaceEventAttribute>;
|
|
18
|
+
};
|
|
19
|
+
export type ContractSurfaceMetricAttribute = {
|
|
20
|
+
readonly name: string;
|
|
21
|
+
readonly classification: "public" | "internal";
|
|
22
|
+
readonly maximumCardinality: number;
|
|
23
|
+
readonly allowedValues: ReadonlyArray<MetricAttributeScalar>;
|
|
24
|
+
};
|
|
25
|
+
export type ContractSurfaceMetric = {
|
|
26
|
+
readonly name: string;
|
|
27
|
+
readonly kind: MetricKind;
|
|
28
|
+
readonly unit: string;
|
|
29
|
+
readonly boundaries: ReadonlyArray<number>;
|
|
30
|
+
readonly attributes: ReadonlyArray<ContractSurfaceMetricAttribute>;
|
|
31
|
+
};
|
|
32
|
+
export type ContractSurfaceAuditAction = {
|
|
33
|
+
readonly action: string;
|
|
34
|
+
readonly resourceType: string;
|
|
35
|
+
readonly allowedOutcomes: ReadonlyArray<AuditOutcome>;
|
|
36
|
+
readonly reasonCodes: ReadonlyArray<string>;
|
|
37
|
+
};
|
|
38
|
+
export type ContractSurfaceAlias = {
|
|
39
|
+
readonly kind: "event" | "metric";
|
|
40
|
+
readonly from: string;
|
|
41
|
+
readonly to: string;
|
|
42
|
+
readonly since: string;
|
|
43
|
+
};
|
|
44
|
+
export type ContractSurface = {
|
|
45
|
+
readonly surface: 1;
|
|
46
|
+
readonly service: string;
|
|
47
|
+
readonly contractVersion: number;
|
|
48
|
+
readonly events: ReadonlyArray<ContractSurfaceEvent>;
|
|
49
|
+
readonly metrics: ReadonlyArray<ContractSurfaceMetric>;
|
|
50
|
+
readonly auditActions: ReadonlyArray<ContractSurfaceAuditAction>;
|
|
51
|
+
readonly aliases: ReadonlyArray<ContractSurfaceAlias>;
|
|
52
|
+
readonly browserEnvelope: {
|
|
53
|
+
readonly version: number;
|
|
54
|
+
readonly batchFields: ReadonlyArray<string>;
|
|
55
|
+
readonly eventFields: ReadonlyArray<string>;
|
|
56
|
+
};
|
|
57
|
+
readonly retentionWindowDays: number;
|
|
58
|
+
};
|
|
59
|
+
export type ContractSurfaceInput<Definition extends TelemetryContractInput> = {
|
|
60
|
+
readonly contract: TelemetryContract<Definition>;
|
|
61
|
+
readonly service: string;
|
|
62
|
+
readonly aliases?: ContractSignalAliasMetadata;
|
|
63
|
+
readonly retentionWindowDays: number;
|
|
64
|
+
};
|
|
65
|
+
export declare const contractSurface: <Definition extends TelemetryContractInput>(input: ContractSurfaceInput<Definition>) => ContractSurface;
|
|
66
|
+
export declare const ContractSurfaceSchema: Schema.Struct<{
|
|
67
|
+
readonly surface: Schema.Literal<1>;
|
|
68
|
+
readonly service: Schema.String;
|
|
69
|
+
readonly contractVersion: Schema.Int;
|
|
70
|
+
readonly events: Schema.$Array<Schema.Struct<{
|
|
71
|
+
readonly name: Schema.String;
|
|
72
|
+
readonly kind: Schema.Literals<readonly ["request", "operation", "domain", "defect", "audit"]>;
|
|
73
|
+
readonly outcomeMeaning: Schema.$Array<Schema.String>;
|
|
74
|
+
readonly attributes: Schema.$Array<Schema.Struct<{
|
|
75
|
+
readonly name: Schema.String;
|
|
76
|
+
readonly required: Schema.Boolean;
|
|
77
|
+
readonly classification: Schema.Literals<readonly ["public", "internal", "sensitive", "forbidden"]>;
|
|
78
|
+
readonly metricLabel: Schema.Boolean;
|
|
79
|
+
}>>;
|
|
80
|
+
}>>;
|
|
81
|
+
readonly metrics: Schema.$Array<Schema.Struct<{
|
|
82
|
+
readonly name: Schema.String;
|
|
83
|
+
readonly kind: Schema.Literals<readonly ["counter", "histogram", "observable_gauge"]>;
|
|
84
|
+
readonly unit: Schema.String;
|
|
85
|
+
readonly boundaries: Schema.$Array<Schema.Number>;
|
|
86
|
+
readonly attributes: Schema.$Array<Schema.Struct<{
|
|
87
|
+
readonly name: Schema.String;
|
|
88
|
+
readonly classification: Schema.Literals<readonly ["public", "internal"]>;
|
|
89
|
+
readonly maximumCardinality: Schema.Int;
|
|
90
|
+
readonly allowedValues: Schema.$Array<Schema.Union<readonly [Schema.String, Schema.Number, Schema.Boolean]>>;
|
|
91
|
+
}>>;
|
|
92
|
+
}>>;
|
|
93
|
+
readonly auditActions: Schema.$Array<Schema.Struct<{
|
|
94
|
+
readonly action: Schema.String;
|
|
95
|
+
readonly resourceType: Schema.String;
|
|
96
|
+
readonly allowedOutcomes: Schema.$Array<Schema.Literals<readonly ["success", "failure", "cancelled", "denied"]>>;
|
|
97
|
+
readonly reasonCodes: Schema.$Array<Schema.String>;
|
|
98
|
+
}>>;
|
|
99
|
+
readonly aliases: Schema.$Array<Schema.Struct<{
|
|
100
|
+
readonly kind: Schema.Literals<readonly ["event", "metric"]>;
|
|
101
|
+
readonly from: Schema.String;
|
|
102
|
+
readonly to: Schema.String;
|
|
103
|
+
readonly since: Schema.String;
|
|
104
|
+
}>>;
|
|
105
|
+
readonly browserEnvelope: Schema.Struct<{
|
|
106
|
+
readonly version: Schema.Int;
|
|
107
|
+
readonly batchFields: Schema.$Array<Schema.String>;
|
|
108
|
+
readonly eventFields: Schema.$Array<Schema.String>;
|
|
109
|
+
}>;
|
|
110
|
+
readonly retentionWindowDays: Schema.Int;
|
|
111
|
+
}>;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
import { browserEnvelopeMetadata } from "../BrowserEvents.js";
|
|
3
|
+
const outcomeMeaning = (kind) => kind === "defect"
|
|
4
|
+
? ["failure"]
|
|
5
|
+
: kind === "audit"
|
|
6
|
+
? ["cancelled", "denied", "failure", "success"]
|
|
7
|
+
: ["cancelled", "failure", "success"];
|
|
8
|
+
const byName = (left, right) => left.name.localeCompare(right.name);
|
|
9
|
+
export const contractSurface = (input) => ({
|
|
10
|
+
surface: 1,
|
|
11
|
+
service: input.service,
|
|
12
|
+
contractVersion: input.contract.version,
|
|
13
|
+
events: [...input.contract.eventByName.values()]
|
|
14
|
+
.map((event) => ({
|
|
15
|
+
name: event.name,
|
|
16
|
+
kind: event.kind,
|
|
17
|
+
outcomeMeaning: outcomeMeaning(event.kind),
|
|
18
|
+
attributes: [...event.attributes.entries()]
|
|
19
|
+
.map(([name, attribute]) => ({
|
|
20
|
+
name,
|
|
21
|
+
required: attribute.required,
|
|
22
|
+
classification: attribute.classification,
|
|
23
|
+
metricLabel: attribute.metricLabel,
|
|
24
|
+
}))
|
|
25
|
+
.sort(byName),
|
|
26
|
+
}))
|
|
27
|
+
.sort(byName),
|
|
28
|
+
metrics: [...input.contract.metricByName.values()]
|
|
29
|
+
.map((metric) => ({
|
|
30
|
+
name: metric.name,
|
|
31
|
+
kind: metric.kind,
|
|
32
|
+
unit: metric.unit,
|
|
33
|
+
boundaries: metric.kind === "histogram" ? [...metric.boundaries] : [],
|
|
34
|
+
attributes: [...metric.attributes.entries()]
|
|
35
|
+
.map(([name, attribute]) => ({
|
|
36
|
+
name,
|
|
37
|
+
classification: attribute.classification,
|
|
38
|
+
maximumCardinality: attribute.maximumCardinality,
|
|
39
|
+
allowedValues: [...(attribute.allowedValues ?? [])],
|
|
40
|
+
}))
|
|
41
|
+
.sort(byName),
|
|
42
|
+
}))
|
|
43
|
+
.sort(byName),
|
|
44
|
+
auditActions: [...input.contract.auditActionByName.values()]
|
|
45
|
+
.map((action) => ({
|
|
46
|
+
action: action.action,
|
|
47
|
+
resourceType: action.resourceType,
|
|
48
|
+
allowedOutcomes: [...action.allowedOutcomes].sort(),
|
|
49
|
+
reasonCodes: [...action.reasonCodes].sort(),
|
|
50
|
+
}))
|
|
51
|
+
.sort((left, right) => left.action.localeCompare(right.action)),
|
|
52
|
+
aliases: [...(input.aliases?.aliases ?? [])]
|
|
53
|
+
.map((alias) => ({
|
|
54
|
+
kind: alias.source.kind,
|
|
55
|
+
from: alias.source.name,
|
|
56
|
+
to: alias.target.name,
|
|
57
|
+
since: alias.since,
|
|
58
|
+
}))
|
|
59
|
+
.sort((left, right) => `${left.kind}\u0000${left.from}\u0000${left.to}`.localeCompare(`${right.kind}\u0000${right.from}\u0000${right.to}`)),
|
|
60
|
+
browserEnvelope: browserEnvelopeMetadata,
|
|
61
|
+
retentionWindowDays: input.retentionWindowDays,
|
|
62
|
+
});
|
|
63
|
+
const PositiveSafeInteger = Schema.Int.check(Schema.isGreaterThan(0), Schema.makeFilter(Number.isSafeInteger, { expected: "a positive safe integer" }));
|
|
64
|
+
const Scalar = Schema.Union([Schema.String, Schema.Number, Schema.Boolean]);
|
|
65
|
+
const EventAttributeDocument = Schema.Struct({
|
|
66
|
+
name: Schema.String,
|
|
67
|
+
required: Schema.Boolean,
|
|
68
|
+
classification: Schema.Literals(["public", "internal", "sensitive", "forbidden"]),
|
|
69
|
+
metricLabel: Schema.Boolean,
|
|
70
|
+
});
|
|
71
|
+
const EventDocument = Schema.Struct({
|
|
72
|
+
name: Schema.String,
|
|
73
|
+
kind: Schema.Literals(["request", "operation", "domain", "defect", "audit"]),
|
|
74
|
+
outcomeMeaning: Schema.Array(Schema.String),
|
|
75
|
+
attributes: Schema.Array(EventAttributeDocument),
|
|
76
|
+
});
|
|
77
|
+
const MetricAttributeDocument = Schema.Struct({
|
|
78
|
+
name: Schema.String,
|
|
79
|
+
classification: Schema.Literals(["public", "internal"]),
|
|
80
|
+
maximumCardinality: Schema.Int,
|
|
81
|
+
allowedValues: Schema.Array(Scalar),
|
|
82
|
+
});
|
|
83
|
+
const MetricDocument = Schema.Struct({
|
|
84
|
+
name: Schema.String,
|
|
85
|
+
kind: Schema.Literals(["counter", "histogram", "observable_gauge"]),
|
|
86
|
+
unit: Schema.String,
|
|
87
|
+
boundaries: Schema.Array(Schema.Number),
|
|
88
|
+
attributes: Schema.Array(MetricAttributeDocument),
|
|
89
|
+
});
|
|
90
|
+
const AuditActionDocument = Schema.Struct({
|
|
91
|
+
action: Schema.String,
|
|
92
|
+
resourceType: Schema.String,
|
|
93
|
+
allowedOutcomes: Schema.Array(Schema.Literals(["success", "failure", "cancelled", "denied"])),
|
|
94
|
+
reasonCodes: Schema.Array(Schema.String),
|
|
95
|
+
});
|
|
96
|
+
const AliasDocument = Schema.Struct({
|
|
97
|
+
kind: Schema.Literals(["event", "metric"]),
|
|
98
|
+
from: Schema.String,
|
|
99
|
+
to: Schema.String,
|
|
100
|
+
since: Schema.String,
|
|
101
|
+
});
|
|
102
|
+
export const ContractSurfaceSchema = Schema.Struct({
|
|
103
|
+
surface: Schema.Literal(1),
|
|
104
|
+
service: Schema.String,
|
|
105
|
+
contractVersion: PositiveSafeInteger,
|
|
106
|
+
events: Schema.Array(EventDocument),
|
|
107
|
+
metrics: Schema.Array(MetricDocument),
|
|
108
|
+
auditActions: Schema.Array(AuditActionDocument),
|
|
109
|
+
aliases: Schema.Array(AliasDocument),
|
|
110
|
+
browserEnvelope: Schema.Struct({
|
|
111
|
+
version: PositiveSafeInteger,
|
|
112
|
+
batchFields: Schema.Array(Schema.String),
|
|
113
|
+
eventFields: Schema.Array(Schema.String),
|
|
114
|
+
}),
|
|
115
|
+
retentionWindowDays: Schema.Int.check(Schema.isGreaterThan(0), Schema.isLessThanOrEqualTo(3_650)),
|
|
116
|
+
});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
export declare const isReservedEventNamePart: (part: string) => boolean;
|
|
3
|
+
export declare const EventName: Schema.brand<Schema.String, "EventName">;
|
|
4
|
+
export type EventName = typeof EventName.Type;
|
|
5
|
+
export declare const isValidEventName: (name: string) => boolean;
|
|
6
|
+
export declare const isValidAttributeName: (name: string) => boolean;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
const eventNamePattern = /^[a-z][a-z0-9_]*(?:\.[a-z][a-z0-9_]*){1,3}$/;
|
|
3
|
+
const attributeNamePattern = /^[a-z][a-z0-9_]*(?:\.[a-z][a-z0-9_]*)+$/;
|
|
4
|
+
const numericIdentifierPattern = /^\d+$/;
|
|
5
|
+
const uuidIdentifierPattern = /^[0-9a-f]{8}(?:_[0-9a-f]{4}){3}_[0-9a-f]{12}$/;
|
|
6
|
+
const longIdentifierPattern = /^(?=[a-z0-9_]{12,}$)(?=.*[a-z])(?=.*\d)[a-z0-9_]+$/;
|
|
7
|
+
const reservedEventParts = new Set([
|
|
8
|
+
"production",
|
|
9
|
+
"prod",
|
|
10
|
+
"staging",
|
|
11
|
+
"stage",
|
|
12
|
+
"development",
|
|
13
|
+
"dev",
|
|
14
|
+
"test",
|
|
15
|
+
"local",
|
|
16
|
+
"sandbox",
|
|
17
|
+
"qa",
|
|
18
|
+
"preview",
|
|
19
|
+
"debug",
|
|
20
|
+
"info",
|
|
21
|
+
"warn",
|
|
22
|
+
"warning",
|
|
23
|
+
"fatal",
|
|
24
|
+
"critical",
|
|
25
|
+
"trace",
|
|
26
|
+
"verbose",
|
|
27
|
+
"severity",
|
|
28
|
+
"success",
|
|
29
|
+
"succeeded",
|
|
30
|
+
"failure",
|
|
31
|
+
"failed",
|
|
32
|
+
"cancelled",
|
|
33
|
+
"canceled",
|
|
34
|
+
"ok",
|
|
35
|
+
"outcome",
|
|
36
|
+
"errored",
|
|
37
|
+
"error",
|
|
38
|
+
]);
|
|
39
|
+
export const isReservedEventNamePart = (part) => reservedEventParts.has(part);
|
|
40
|
+
export const EventName = Schema.String.check(Schema.makeFilter((name) => isValidEventName(name), { expected: "a valid telemetry event name" })).pipe(Schema.brand("EventName"));
|
|
41
|
+
export const isValidEventName = (name) => {
|
|
42
|
+
if (name.length > 128 || !eventNamePattern.test(name)) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
if (name === "browser.error") {
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
return name
|
|
49
|
+
.split(".")
|
|
50
|
+
.every((part) => !isReservedEventNamePart(part) &&
|
|
51
|
+
!numericIdentifierPattern.test(part) &&
|
|
52
|
+
!uuidIdentifierPattern.test(part) &&
|
|
53
|
+
!longIdentifierPattern.test(part));
|
|
54
|
+
};
|
|
55
|
+
export const isValidAttributeName = (name) => name.length <= 128 && attributeNamePattern.test(name);
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { Context, Effect } from "effect";
|
|
2
|
+
import { AuditOutcome, type AuditActorInput } from "../audit/AuditRecord.js";
|
|
3
|
+
import { CorrelationContext } from "../Correlation.js";
|
|
4
|
+
import { type AttributeDefinitionsInput, type AuditActionDefinitionInput, type CompiledEventDefinition, type EventContractRegistry, type CompiledAuditActionDefinition, type TelemetryContract, type TelemetryContractInput } from "./TelemetryContract.js";
|
|
5
|
+
import type { BrowserEventError, BrowserTraceContext } from "../BrowserEvents.js";
|
|
6
|
+
import { type AttributeValue, ErrorContext, type EventAttributes, EventOutcome, EventSeverity, HttpContext, type TelemetryEvent } from "./TelemetryEvent.js";
|
|
7
|
+
import type { PolicyRedaction } from "../policy/PolicyTransform.js";
|
|
8
|
+
import { InvalidTelemetryEvent } from "./TelemetryContractError.js";
|
|
9
|
+
export type EventAdmissionMetadata = {
|
|
10
|
+
readonly policyDroppedAttributes: number;
|
|
11
|
+
};
|
|
12
|
+
export type BrowserTelemetryEvent = {
|
|
13
|
+
readonly id: string;
|
|
14
|
+
readonly name: string;
|
|
15
|
+
readonly occurredAt: number;
|
|
16
|
+
readonly attributes: EventAttributes;
|
|
17
|
+
readonly error?: BrowserEventError;
|
|
18
|
+
readonly trace?: BrowserTraceContext;
|
|
19
|
+
readonly admission: EventAdmissionMetadata;
|
|
20
|
+
};
|
|
21
|
+
export type BrowserEventBatchAdmission = {
|
|
22
|
+
readonly commit: Effect.Effect<void>;
|
|
23
|
+
};
|
|
24
|
+
declare const TelemetryEventSink_base: Context.ServiceClass<TelemetryEventSink, "@equipe-tech/observability/TelemetryEventSink", {
|
|
25
|
+
readonly record: (event: TelemetryEvent, admission: EventAdmissionMetadata) => Effect.Effect<void, InvalidTelemetryEvent>;
|
|
26
|
+
readonly admitBrowserBatch: (events: ReadonlyArray<BrowserTelemetryEvent>) => Effect.Effect<BrowserEventBatchAdmission, InvalidTelemetryEvent>;
|
|
27
|
+
}>;
|
|
28
|
+
export declare class TelemetryEventSink extends TelemetryEventSink_base {
|
|
29
|
+
}
|
|
30
|
+
type RequiredAttributeNames<Attributes extends AttributeDefinitionsInput> = {
|
|
31
|
+
readonly [Name in keyof Attributes]: Attributes[Name]["required"] extends true ? Name : never;
|
|
32
|
+
}[keyof Attributes];
|
|
33
|
+
type EventAttributesOf<Attributes extends AttributeDefinitionsInput> = {
|
|
34
|
+
readonly [Name in RequiredAttributeNames<Attributes>]: AttributeValue;
|
|
35
|
+
} & {
|
|
36
|
+
readonly [Name in Exclude<keyof Attributes, RequiredAttributeNames<Attributes>>]?: AttributeValue;
|
|
37
|
+
};
|
|
38
|
+
type EventPayloadBase<Attributes extends AttributeDefinitionsInput> = {
|
|
39
|
+
readonly timestamp?: string;
|
|
40
|
+
readonly severity?: EventSeverity;
|
|
41
|
+
readonly correlation?: CorrelationContext;
|
|
42
|
+
readonly attributes: EventAttributesOf<Attributes>;
|
|
43
|
+
};
|
|
44
|
+
type AuditPayloadForAction<Action extends AuditActionDefinitionInput> = {
|
|
45
|
+
readonly outcome: Action["allowedOutcomes"][number];
|
|
46
|
+
readonly audit: {
|
|
47
|
+
readonly action: Action["action"];
|
|
48
|
+
readonly actor: AuditActorInput;
|
|
49
|
+
readonly resourceType: Action["resourceType"];
|
|
50
|
+
readonly resourceId: string;
|
|
51
|
+
readonly reasonCode?: string;
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
type AuditPayload<Definition extends TelemetryContractInput> = {
|
|
55
|
+
readonly [Alias in keyof Definition["auditActions"]]: AuditPayloadForAction<Definition["auditActions"][Alias]>;
|
|
56
|
+
}[keyof Definition["auditActions"]];
|
|
57
|
+
type EventPayloadForKind<Kind, Attributes extends AttributeDefinitionsInput, Definition extends TelemetryContractInput> = Kind extends "request" ? EventPayloadBase<Attributes> & {
|
|
58
|
+
readonly outcome: EventOutcome;
|
|
59
|
+
readonly durationMs: number;
|
|
60
|
+
readonly http: HttpContext;
|
|
61
|
+
} : Kind extends "operation" ? EventPayloadBase<Attributes> & {
|
|
62
|
+
readonly outcome: EventOutcome;
|
|
63
|
+
readonly durationMs: number;
|
|
64
|
+
} : Kind extends "domain" ? EventPayloadBase<Attributes> & {
|
|
65
|
+
readonly outcome: EventOutcome;
|
|
66
|
+
} : Kind extends "defect" ? EventPayloadBase<Attributes> & {
|
|
67
|
+
readonly outcome?: never;
|
|
68
|
+
readonly error: ErrorContext;
|
|
69
|
+
} : Kind extends "audit" ? EventPayloadBase<Attributes> & AuditPayload<Definition> : never;
|
|
70
|
+
export type EventPayloadOf<Definition extends TelemetryContractInput, Alias extends keyof Definition["events"] & string> = EventPayloadForKind<Definition["events"][Alias]["kind"], Definition["events"][Alias]["attributes"], Definition>;
|
|
71
|
+
export type EmitReceipt = {
|
|
72
|
+
readonly decision: "recorded";
|
|
73
|
+
readonly event: TelemetryEvent;
|
|
74
|
+
readonly redactions: ReadonlyArray<PolicyRedaction>;
|
|
75
|
+
readonly admission: EventAdmissionMetadata;
|
|
76
|
+
readonly contractProvenance: string;
|
|
77
|
+
} | {
|
|
78
|
+
readonly decision: "sampled_out";
|
|
79
|
+
readonly name: string;
|
|
80
|
+
readonly contractProvenance: string;
|
|
81
|
+
};
|
|
82
|
+
export type EventProducer<Definition extends TelemetryContractInput> = {
|
|
83
|
+
readonly emit: <Alias extends keyof Definition["events"] & string>(alias: Alias, payload: EventPayloadOf<Definition, Alias>) => Effect.Effect<EmitReceipt, InvalidTelemetryEvent, TelemetryEventSink>;
|
|
84
|
+
};
|
|
85
|
+
type EmittedAttributes = {
|
|
86
|
+
readonly [attributeName: string]: AttributeValue | undefined;
|
|
87
|
+
};
|
|
88
|
+
type AuditContextInput = {
|
|
89
|
+
readonly action: string;
|
|
90
|
+
readonly actor: AuditActorInput;
|
|
91
|
+
readonly resourceType: string;
|
|
92
|
+
readonly resourceId: string;
|
|
93
|
+
readonly reasonCode?: string;
|
|
94
|
+
};
|
|
95
|
+
type AdmissionContract = EventContractRegistry & {
|
|
96
|
+
readonly auditActionByName: ReadonlyMap<string, CompiledAuditActionDefinition>;
|
|
97
|
+
};
|
|
98
|
+
export type CanonicalEventPayload = {
|
|
99
|
+
readonly timestamp?: string;
|
|
100
|
+
readonly severity?: EventSeverity;
|
|
101
|
+
readonly correlation?: CorrelationContext;
|
|
102
|
+
readonly attributes: EmittedAttributes;
|
|
103
|
+
readonly outcome?: AuditOutcome;
|
|
104
|
+
readonly durationMs?: number;
|
|
105
|
+
readonly http?: HttpContext;
|
|
106
|
+
readonly error?: ErrorContext;
|
|
107
|
+
readonly audit?: AuditContextInput;
|
|
108
|
+
};
|
|
109
|
+
export declare const admitEvent: (contract: AdmissionContract, definition: CompiledEventDefinition, payload: CanonicalEventPayload) => Effect.Effect<{
|
|
110
|
+
decision: "sampled_out";
|
|
111
|
+
name: string & import("effect/Brand").Brand<"EventName">;
|
|
112
|
+
event?: never;
|
|
113
|
+
redactions?: never;
|
|
114
|
+
admission?: never;
|
|
115
|
+
} | {
|
|
116
|
+
name?: never;
|
|
117
|
+
decision: "recorded";
|
|
118
|
+
event: TelemetryEvent;
|
|
119
|
+
redactions: readonly PolicyRedaction[];
|
|
120
|
+
admission: EventAdmissionMetadata;
|
|
121
|
+
}, InvalidTelemetryEvent, never>;
|
|
122
|
+
export declare const makeEventProducer: <const Definition extends TelemetryContractInput>(contract: TelemetryContract<Definition>) => EventProducer<Definition>;
|
|
123
|
+
export {};
|