brass-runtime 1.16.1 → 1.17.0
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 +4 -5
- package/dist/{chunk-MT3OWDPC.mjs → chunk-4P2HHGAX.mjs} +28 -0
- package/dist/{chunk-HLWLMW2F.mjs → chunk-6RY2FFN4.mjs} +2 -2
- package/dist/{chunk-BABBZK4Y.js → chunk-7X3K5RMS.js} +2 -2
- package/dist/{chunk-VN44DYYT.cjs → chunk-7ZPEZ57L.cjs} +4 -4
- package/dist/{chunk-CIZFIMK5.js → chunk-BKK77SBA.js} +28 -0
- package/dist/{chunk-76YMRMH2.cjs → chunk-F6XWZQY4.cjs} +25 -25
- package/dist/{chunk-DNFO2EIZ.mjs → chunk-SK7UZRNI.mjs} +1 -1
- package/dist/{chunk-AVNQLJ5V.js → chunk-VWIPB6I5.js} +1 -1
- package/dist/{chunk-ENKODRU3.cjs → chunk-WBGRHGBP.cjs} +29 -1
- package/dist/http/index.cjs +4 -4
- package/dist/http/index.d.ts +1 -1
- package/dist/http/index.js +1 -1
- package/dist/http/index.mjs +1 -1
- package/dist/observability/index.cjs +5 -3
- package/dist/observability/index.d.ts +2 -2
- package/dist/observability/index.js +4 -2
- package/dist/observability/index.mjs +4 -2
- package/dist/perf/cli.cjs +18 -18
- package/dist/perf/cli.js +3 -3
- package/dist/perf/cli.mjs +3 -3
- package/dist/perf/index.cjs +5 -5
- package/dist/perf/index.js +3 -3
- package/dist/perf/index.mjs +3 -3
- package/dist/{server-GJPg8ZSG.d.ts → server-D6JZ15_e.d.ts} +12 -1
- package/docs/README.md +2 -0
- package/docs/ai/PUBLIC_API.md +3 -0
- package/docs/framework-integrations.md +38 -0
- package/docs/frameworks/angular.md +153 -0
- package/docs/frameworks/express.md +125 -0
- package/docs/frameworks/fastify.md +124 -0
- package/docs/frameworks/nestjs.md +282 -0
- package/docs/frameworks/nextjs.md +147 -0
- package/docs/frameworks/react.md +139 -0
- package/docs/frameworks/vanilla.md +224 -0
- package/docs/nestjs.md +6 -0
- package/docs/observability-framework-examples.md +12 -0
- package/docs/observability.md +107 -0
- package/package.json +1 -1
package/dist/perf/cli.cjs
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
var
|
|
18
|
+
var _chunk7ZPEZ57Lcjs = require('../chunk-7ZPEZ57L.cjs');
|
|
19
19
|
require('../chunk-PD4EJTQC.cjs');
|
|
20
20
|
require('../chunk-KQLYONSE.cjs');
|
|
21
21
|
require('../chunk-5EC274J5.cjs');
|
|
@@ -24,8 +24,8 @@ require('../chunk-KZJQ723N.cjs');
|
|
|
24
24
|
require('../chunk-SA6HUJVI.cjs');
|
|
25
25
|
require('../chunk-AGR5B2BC.cjs');
|
|
26
26
|
require('../chunk-JF5WGYJJ.cjs');
|
|
27
|
-
require('../chunk-
|
|
28
|
-
require('../chunk-
|
|
27
|
+
require('../chunk-F6XWZQY4.cjs');
|
|
28
|
+
require('../chunk-WBGRHGBP.cjs');
|
|
29
29
|
require('../chunk-52PPNNI4.cjs');
|
|
30
30
|
require('../chunk-3LOYJFRR.cjs');
|
|
31
31
|
require('../chunk-GLE2WY7Z.cjs');
|
|
@@ -37,22 +37,22 @@ require('../chunk-OBGZSXTJ.cjs');
|
|
|
37
37
|
async function main(argv) {
|
|
38
38
|
const cli = parseArgs(argv);
|
|
39
39
|
if (cli.profile === "runtime-ab") {
|
|
40
|
-
const report2 = await
|
|
41
|
-
await printReport(cli, report2,
|
|
40
|
+
const report2 = await _chunk7ZPEZ57Lcjs.profileRuntimeAb.call(void 0, cli.runtimeAb);
|
|
41
|
+
await printReport(cli, report2, _chunk7ZPEZ57Lcjs.formatRuntimeAbReport.call(void 0, report2));
|
|
42
42
|
return;
|
|
43
43
|
}
|
|
44
44
|
if (cli.profile === "runtime-soak") {
|
|
45
|
-
const report2 = await
|
|
46
|
-
await printReport(cli, report2,
|
|
45
|
+
const report2 = await _chunk7ZPEZ57Lcjs.profileRuntimeSoak.call(void 0, cli.runtimeSoak);
|
|
46
|
+
await printReport(cli, report2, _chunk7ZPEZ57Lcjs.formatRuntimeSoakReport.call(void 0, report2));
|
|
47
47
|
return;
|
|
48
48
|
}
|
|
49
49
|
if (cli.profile === "http-memory") {
|
|
50
|
-
const report2 = await
|
|
51
|
-
await printReport(cli, report2,
|
|
50
|
+
const report2 = await _chunk7ZPEZ57Lcjs.profileHttpMemoryLab.call(void 0, cli.httpMemory);
|
|
51
|
+
await printReport(cli, report2, _chunk7ZPEZ57Lcjs.formatHttpMemoryLabReport.call(void 0, report2));
|
|
52
52
|
return;
|
|
53
53
|
}
|
|
54
|
-
const report = await
|
|
55
|
-
await printReport(cli, report,
|
|
54
|
+
const report = await _chunk7ZPEZ57Lcjs.runBrassPerformanceProfile.call(void 0, cli.options);
|
|
55
|
+
await printReport(cli, report, _chunk7ZPEZ57Lcjs.formatPerformanceReport.call(void 0, report));
|
|
56
56
|
}
|
|
57
57
|
function parseArgs(argv) {
|
|
58
58
|
let json = envBool("BRASS_PERF_JSON", false);
|
|
@@ -295,14 +295,14 @@ async function maybeHandleHistory(cli, report) {
|
|
|
295
295
|
cliProfile: cli.profile
|
|
296
296
|
}
|
|
297
297
|
};
|
|
298
|
-
const entry =
|
|
299
|
-
const historyPath = config.recordHistory ? await
|
|
300
|
-
const savedBaseline = config.saveBaseline ? await
|
|
301
|
-
const loadedBaseline = config.compareBaseline ? await
|
|
298
|
+
const entry = _chunk7ZPEZ57Lcjs.createPerfHistoryEntry.call(void 0, cli.profile, report, storeOptions);
|
|
299
|
+
const historyPath = config.recordHistory ? await _chunk7ZPEZ57Lcjs.writePerfHistoryEntry.call(void 0, entry, storeOptions) : void 0;
|
|
300
|
+
const savedBaseline = config.saveBaseline ? await _chunk7ZPEZ57Lcjs.savePerfBaseline.call(void 0, config.saveBaseline, entry, storeOptions) : void 0;
|
|
301
|
+
const loadedBaseline = config.compareBaseline ? await _chunk7ZPEZ57Lcjs.loadPerfBaseline.call(void 0, config.compareBaseline, storeOptions) : void 0;
|
|
302
302
|
if (config.compareBaseline && !loadedBaseline) {
|
|
303
303
|
throw new Error(`Perf baseline '${config.compareBaseline}' was not found`);
|
|
304
304
|
}
|
|
305
|
-
const comparison = loadedBaseline ?
|
|
305
|
+
const comparison = loadedBaseline ? _chunk7ZPEZ57Lcjs.comparePerfToBaseline.call(void 0, entry, loadedBaseline, config.thresholds) : void 0;
|
|
306
306
|
return Object.freeze({
|
|
307
307
|
entry,
|
|
308
308
|
...historyPath !== void 0 ? { historyPath } : {},
|
|
@@ -317,7 +317,7 @@ function formatCliHistory(history) {
|
|
|
317
317
|
if (history.savedBaselinePath) lines.push(`- baseline saved: ${history.savedBaselinePath}`);
|
|
318
318
|
if (history.comparison) {
|
|
319
319
|
lines.push("");
|
|
320
|
-
lines.push(
|
|
320
|
+
lines.push(_chunk7ZPEZ57Lcjs.formatPerfBaselineComparison.call(void 0, history.comparison));
|
|
321
321
|
}
|
|
322
322
|
return lines.join("\n");
|
|
323
323
|
}
|
|
@@ -335,7 +335,7 @@ function parseRuntimeVariant(value) {
|
|
|
335
335
|
throw new Error(`Invalid runtime variant: ${value}`);
|
|
336
336
|
}
|
|
337
337
|
function parseVariants(value) {
|
|
338
|
-
const allowed = new Set(
|
|
338
|
+
const allowed = new Set(_chunk7ZPEZ57Lcjs.HTTP_PROFILE_VARIANTS);
|
|
339
339
|
return Object.freeze(value.split(",").map((item) => item.trim()).filter(Boolean).map((item) => {
|
|
340
340
|
if (!allowed.has(item)) {
|
|
341
341
|
throw new Error(`Invalid HTTP profile variant: ${item}`);
|
package/dist/perf/cli.js
CHANGED
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
runBrassPerformanceProfile,
|
|
16
16
|
savePerfBaseline,
|
|
17
17
|
writePerfHistoryEntry
|
|
18
|
-
} from "../chunk-
|
|
18
|
+
} from "../chunk-7X3K5RMS.js";
|
|
19
19
|
import "../chunk-5QC7LRZ3.js";
|
|
20
20
|
import "../chunk-74ZTY6CP.js";
|
|
21
21
|
import "../chunk-MIIYDLGM.js";
|
|
@@ -24,8 +24,8 @@ import "../chunk-7JIJOVCT.js";
|
|
|
24
24
|
import "../chunk-UCUBNWM2.js";
|
|
25
25
|
import "../chunk-6IXXWIUM.js";
|
|
26
26
|
import "../chunk-L2SYFEBS.js";
|
|
27
|
-
import "../chunk-
|
|
28
|
-
import "../chunk-
|
|
27
|
+
import "../chunk-VWIPB6I5.js";
|
|
28
|
+
import "../chunk-BKK77SBA.js";
|
|
29
29
|
import "../chunk-RKGKFN2A.js";
|
|
30
30
|
import "../chunk-3Y2RIUMM.js";
|
|
31
31
|
import "../chunk-FH2X7BVP.js";
|
package/dist/perf/cli.mjs
CHANGED
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
runBrassPerformanceProfile,
|
|
16
16
|
savePerfBaseline,
|
|
17
17
|
writePerfHistoryEntry
|
|
18
|
-
} from "../chunk-
|
|
18
|
+
} from "../chunk-6RY2FFN4.mjs";
|
|
19
19
|
import "../chunk-EOC4UHBS.mjs";
|
|
20
20
|
import "../chunk-7CMJS3QE.mjs";
|
|
21
21
|
import "../chunk-5VRJNBLZ.mjs";
|
|
@@ -24,8 +24,8 @@ import "../chunk-FHQGHPMO.mjs";
|
|
|
24
24
|
import "../chunk-B5JD23U7.mjs";
|
|
25
25
|
import "../chunk-2HQTDLHF.mjs";
|
|
26
26
|
import "../chunk-A2OM6NEH.mjs";
|
|
27
|
-
import "../chunk-
|
|
28
|
-
import "../chunk-
|
|
27
|
+
import "../chunk-SK7UZRNI.mjs";
|
|
28
|
+
import "../chunk-4P2HHGAX.mjs";
|
|
29
29
|
import "../chunk-EJ6BPYVR.mjs";
|
|
30
30
|
import "../chunk-PWC3RBQE.mjs";
|
|
31
31
|
import "../chunk-GYM3LLGS.mjs";
|
package/dist/perf/index.cjs
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
|
|
33
|
-
var
|
|
33
|
+
var _chunk7ZPEZ57Lcjs = require('../chunk-7ZPEZ57L.cjs');
|
|
34
34
|
require('../chunk-PD4EJTQC.cjs');
|
|
35
35
|
require('../chunk-KQLYONSE.cjs');
|
|
36
36
|
require('../chunk-5EC274J5.cjs');
|
|
@@ -39,8 +39,8 @@ require('../chunk-KZJQ723N.cjs');
|
|
|
39
39
|
require('../chunk-SA6HUJVI.cjs');
|
|
40
40
|
require('../chunk-AGR5B2BC.cjs');
|
|
41
41
|
require('../chunk-JF5WGYJJ.cjs');
|
|
42
|
-
require('../chunk-
|
|
43
|
-
require('../chunk-
|
|
42
|
+
require('../chunk-F6XWZQY4.cjs');
|
|
43
|
+
require('../chunk-WBGRHGBP.cjs');
|
|
44
44
|
require('../chunk-52PPNNI4.cjs');
|
|
45
45
|
require('../chunk-3LOYJFRR.cjs');
|
|
46
46
|
require('../chunk-GLE2WY7Z.cjs');
|
|
@@ -50,7 +50,7 @@ require('../chunk-OBGZSXTJ.cjs');
|
|
|
50
50
|
|
|
51
51
|
// src/perf/budget.ts
|
|
52
52
|
async function runRuntimePerfBudget(options = {}) {
|
|
53
|
-
const ab = await
|
|
53
|
+
const ab = await _chunk7ZPEZ57Lcjs.profileRuntimeAb.call(void 0, {
|
|
54
54
|
...options,
|
|
55
55
|
thresholds: {
|
|
56
56
|
maxRegressionPercent: _nullishCoalesce(_optionalChain([options, 'access', _ => _.thresholds, 'optionalAccess', _2 => _2.maxRegressionPercent]), () => ( 50)),
|
|
@@ -138,4 +138,4 @@ function positiveNumber(value, fallback) {
|
|
|
138
138
|
|
|
139
139
|
|
|
140
140
|
|
|
141
|
-
exports.HTTP_PROFILE_VARIANTS =
|
|
141
|
+
exports.HTTP_PROFILE_VARIANTS = _chunk7ZPEZ57Lcjs.HTTP_PROFILE_VARIANTS; exports.captureMemorySnapshot = _chunk7ZPEZ57Lcjs.captureMemorySnapshot; exports.comparePerfToBaseline = _chunk7ZPEZ57Lcjs.comparePerfToBaseline; exports.compareRuntimeProfiles = _chunk7ZPEZ57Lcjs.compareRuntimeProfiles; exports.createPerfHistoryEntry = _chunk7ZPEZ57Lcjs.createPerfHistoryEntry; exports.defaultPerfHistoryDirectory = _chunk7ZPEZ57Lcjs.defaultPerfHistoryDirectory; exports.diagnoseRuntimeProfile = _chunk7ZPEZ57Lcjs.diagnoseRuntimeProfile; exports.diffMemorySnapshots = _chunk7ZPEZ57Lcjs.diffMemorySnapshots; exports.extractPerfMetrics = _chunk7ZPEZ57Lcjs.extractPerfMetrics; exports.forceGc = _chunk7ZPEZ57Lcjs.forceGc; exports.formatHttpMemoryLabReport = _chunk7ZPEZ57Lcjs.formatHttpMemoryLabReport; exports.formatPerfBaselineComparison = _chunk7ZPEZ57Lcjs.formatPerfBaselineComparison; exports.formatPerformanceReport = _chunk7ZPEZ57Lcjs.formatPerformanceReport; exports.formatRuntimeAbReport = _chunk7ZPEZ57Lcjs.formatRuntimeAbReport; exports.formatRuntimePerfBudgetReport = formatRuntimePerfBudgetReport; exports.formatRuntimeSoakReport = _chunk7ZPEZ57Lcjs.formatRuntimeSoakReport; exports.hasGc = _chunk7ZPEZ57Lcjs.hasGc; exports.loadPerfBaseline = _chunk7ZPEZ57Lcjs.loadPerfBaseline; exports.makePerfRecorder = _chunk7ZPEZ57Lcjs.makePerfRecorder; exports.profileHttpLayers = _chunk7ZPEZ57Lcjs.profileHttpLayers; exports.profileHttpMemoryLab = _chunk7ZPEZ57Lcjs.profileHttpMemoryLab; exports.profileMemoryRetention = _chunk7ZPEZ57Lcjs.profileMemoryRetention; exports.profileRuntimeAb = _chunk7ZPEZ57Lcjs.profileRuntimeAb; exports.profileRuntimePrimitives = _chunk7ZPEZ57Lcjs.profileRuntimePrimitives; exports.profileRuntimeSoak = _chunk7ZPEZ57Lcjs.profileRuntimeSoak; exports.readPerfHistory = _chunk7ZPEZ57Lcjs.readPerfHistory; exports.recommendPerformance = _chunk7ZPEZ57Lcjs.recommendPerformance; exports.recordPerfHistoryRun = _chunk7ZPEZ57Lcjs.recordPerfHistoryRun; exports.runBrassPerformanceProfile = _chunk7ZPEZ57Lcjs.runBrassPerformanceProfile; exports.runRuntimePerfBudget = runRuntimePerfBudget; exports.savePerfBaseline = _chunk7ZPEZ57Lcjs.savePerfBaseline; exports.summarizePerfEvents = _chunk7ZPEZ57Lcjs.summarizePerfEvents; exports.writePerfHistoryEntry = _chunk7ZPEZ57Lcjs.writePerfHistoryEntry;
|
package/dist/perf/index.js
CHANGED
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
savePerfBaseline,
|
|
31
31
|
summarizePerfEvents,
|
|
32
32
|
writePerfHistoryEntry
|
|
33
|
-
} from "../chunk-
|
|
33
|
+
} from "../chunk-7X3K5RMS.js";
|
|
34
34
|
import "../chunk-5QC7LRZ3.js";
|
|
35
35
|
import "../chunk-74ZTY6CP.js";
|
|
36
36
|
import "../chunk-MIIYDLGM.js";
|
|
@@ -39,8 +39,8 @@ import "../chunk-7JIJOVCT.js";
|
|
|
39
39
|
import "../chunk-UCUBNWM2.js";
|
|
40
40
|
import "../chunk-6IXXWIUM.js";
|
|
41
41
|
import "../chunk-L2SYFEBS.js";
|
|
42
|
-
import "../chunk-
|
|
43
|
-
import "../chunk-
|
|
42
|
+
import "../chunk-VWIPB6I5.js";
|
|
43
|
+
import "../chunk-BKK77SBA.js";
|
|
44
44
|
import "../chunk-RKGKFN2A.js";
|
|
45
45
|
import "../chunk-3Y2RIUMM.js";
|
|
46
46
|
import "../chunk-FH2X7BVP.js";
|
package/dist/perf/index.mjs
CHANGED
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
savePerfBaseline,
|
|
31
31
|
summarizePerfEvents,
|
|
32
32
|
writePerfHistoryEntry
|
|
33
|
-
} from "../chunk-
|
|
33
|
+
} from "../chunk-6RY2FFN4.mjs";
|
|
34
34
|
import "../chunk-EOC4UHBS.mjs";
|
|
35
35
|
import "../chunk-7CMJS3QE.mjs";
|
|
36
36
|
import "../chunk-5VRJNBLZ.mjs";
|
|
@@ -39,8 +39,8 @@ import "../chunk-FHQGHPMO.mjs";
|
|
|
39
39
|
import "../chunk-B5JD23U7.mjs";
|
|
40
40
|
import "../chunk-2HQTDLHF.mjs";
|
|
41
41
|
import "../chunk-A2OM6NEH.mjs";
|
|
42
|
-
import "../chunk-
|
|
43
|
-
import "../chunk-
|
|
42
|
+
import "../chunk-SK7UZRNI.mjs";
|
|
43
|
+
import "../chunk-4P2HHGAX.mjs";
|
|
44
44
|
import "../chunk-EJ6BPYVR.mjs";
|
|
45
45
|
import "../chunk-PWC3RBQE.mjs";
|
|
46
46
|
import "../chunk-GYM3LLGS.mjs";
|
|
@@ -412,6 +412,17 @@ type ObservabilityOtlpOptions = {
|
|
|
412
412
|
readonly retry?: ExportRetryOptions;
|
|
413
413
|
readonly pipeline?: ExportPipelineTuning;
|
|
414
414
|
};
|
|
415
|
+
type ObservabilityOtlpSignal = "metrics" | "traces" | "logs";
|
|
416
|
+
type MakeOtlpOptionsInput = {
|
|
417
|
+
readonly endpoint: string;
|
|
418
|
+
readonly headers?: ObservabilityOtlpOptions["headers"];
|
|
419
|
+
readonly fetch?: ObservabilityOtlpOptions["fetch"];
|
|
420
|
+
readonly timeoutMs?: ObservabilityOtlpOptions["timeoutMs"];
|
|
421
|
+
readonly retry?: ObservabilityOtlpOptions["retry"];
|
|
422
|
+
readonly pipeline?: ObservabilityOtlpOptions["pipeline"];
|
|
423
|
+
readonly signals?: readonly ObservabilityOtlpSignal[];
|
|
424
|
+
};
|
|
425
|
+
declare function makeOtlpOptions(input: MakeOtlpOptionsInput): ObservabilityOtlpOptions;
|
|
415
426
|
type ObservabilityOptions = {
|
|
416
427
|
readonly serviceName?: string;
|
|
417
428
|
readonly serviceVersion?: string;
|
|
@@ -672,4 +683,4 @@ type ObservedHttpServerResult<A> = {
|
|
|
672
683
|
declare function runObservedHttpServerEffect<R extends object = {}, E = never, A = never>(observability: Observability, input: RequestObservabilityContextInput, effect: Async<R, E, A>, options?: HttpServerObservabilityOptions<A>, env?: R, runtimeOptions?: RequestObservabilityRuntimeOptions<R>): Promise<ObservedHttpServerResult<A>>;
|
|
673
684
|
declare function observeHttpServerRequest<A>(observability: Observability, input: RequestObservabilityContextInput, handler: (ctx: RequestObservabilityContext) => Promise<A>, options?: HttpServerObservabilityOptions<A>): Promise<ObservedHttpServerResult<A>>;
|
|
674
685
|
|
|
675
|
-
export { type
|
|
686
|
+
export { type RuntimeHealthOptions as $, type ObservabilityRequestEnvInput as A, type ObservabilityRuntimeEnv as B, type CardinalityConfig as C, type ObservabilityTraceExportResult as D, type ExportBatchResult as E, type ObservedHttpServerResult as F, type OtlpAttributeValue as G, type HealthCheck as H, type InjectTraceContextOptions as I, type OtlpExportOptions as J, type OtlpFetch as K, type LogLevel as L, type MakeOtlpOptionsInput as M, type OtlpHttpExportResult as N, type Observability as O, type OtlpHttpExporterOptions as P, type OtlpHttpResponse as Q, type RequestObservabilityContextInput as R, type SpanAttributes as S, type TraceContextCarrier as T, PROMETHEUS_CONTENT_TYPE as U, type PrometheusMetricsExporter as V, type PrometheusMetricsOptions as W, type RedactionConfig as X, type RedactionOptions as Y, type RequestObservabilityRuntimeOptions as Z, type ResolvedTraceSampling as _, type RequestObservabilityContext as a, spanLink as a$, type RuntimeHealthReport as a0, type RuntimeMetricsSinkOptions as a1, type SpanLink as a2, type SpanOptions as a3, type SpanSource as a4, type StructuredLogRecord as a5, type StructuredLogSinkOptions as a6, type StructuredLogSource as a7, type TraceContextHeaderValue as a8, type TraceSamplingConfig as a9, makeOtlpOptions as aA, makePrometheusMetricsExporter as aB, makeRequestObservabilityContext as aC, makeRuntimeHealth as aD, makeRuntimeMetricsSink as aE, makeStructuredLogSink as aF, makeTraceSampler as aG, metricsSnapshotToOtlp as aH, normalizeHttpRoute as aI, normalizeSpanId as aJ, normalizeTraceId as aK, observeHttpServerRequest as aL, otlpAnyValue as aM, parseBaggage as aN, parseTraceparent as aO, postOtlpJson as aP, ratioSampler as aQ, readiness as aR, resolveRequestBaggage as aS, resolveRequestTraceSeed as aT, resolveTraceSampling as aU, runObservedHttpServerEffect as aV, runtimeHealth as aW, sanitizeHttpTarget as aX, shouldSampleWith as aY, snapshotRuntimeHealth as aZ, spanEvent as a_, type TraceSamplingOptions as aa, type TraceSamplingRule as ab, alwaysOffSampler as ac, alwaysOnSampler as ad, currentBaggage as ae, currentSpanLink as af, defaultStructuredLogWriter as ag, exemplarFromTraceContext as ah, exportWithRetry as ai, extractBaggage as aj, extractTraceContext as ak, formatBaggage as al, formatPrometheusMetrics as am, formatStructuredLog as an, formatTraceparent as ao, healthToHttpResponse as ap, injectBaggage as aq, injectTraceContext as ar, logEffect as as, makeCardinalityLimitedMetrics as at, makeExportPipeline as au, makeObservability as av, makeObservabilityRedactor as aw, makeOtlpHttpLogExporter as ax, makeOtlpHttpMetricsExporter as ay, makeOtlpHttpSpanExporter as az, type ObservabilityOptions as b, spansToOtlp as b0, structuredLogsToOtlp as b1, toOtlpAttributes as b2, unixNanoFromMs as b3, withBaggage as b4, withLogContext as b5, withSpan as b6, withTimeout as b7, type CardinalityLimiterOptions as c, type ExportPipeline as d, type ExportPipelineFlushOptions as e, type ExportPipelineFlushResult as f, type ExportPipelineOptions as g, type ExportPipelineStats as h, type ExportPipelineTuning as i, type ExportRetryOptions as j, type ExportSignal as k, type HealthCheckResult as l, type HealthHttpResponse as m, type HealthStatus as n, type HttpServerObservabilityLogOptions as o, type HttpServerObservabilityOptions as p, type HttpServerObservabilitySpanOptions as q, type HttpServerOutcome as r, OTLP_JSON_CONTENT_TYPE as s, type ObservabilityExporters as t, type ObservabilityFlushError as u, type ObservabilityFlushResult as v, type ObservabilityLogExportResult as w, type ObservabilityOtlpOptions as x, type ObservabilityOtlpSignal as y, type ObservabilityRedactor as z };
|
package/docs/README.md
CHANGED
|
@@ -6,6 +6,8 @@ Start here:
|
|
|
6
6
|
- **[Architecture](./ARCHITECTURE.md)** — how the runtime is structured
|
|
7
7
|
- **[Cancellation & interruption](./cancellation.md)** — interruption semantics, scopes, and cancellable `Async`
|
|
8
8
|
- **[Observability](./observability.md)** — hooks, events, sinks, tracing, and HTTP policy context
|
|
9
|
+
- **[Framework integrations](./framework-integrations.md)** — Vanilla, React, Next.js, Angular, Express, Fastify, and Nest patterns
|
|
10
|
+
- **[NestJS integration](./frameworks/nestjs.md)** — Brass module, Grafana/OTLP observability, HTTP client DI, and inbound spans
|
|
9
11
|
- **[HTTP client](./http.md)** — ZIO-style HTTP built on brass-runtime
|
|
10
12
|
- **[HTTP recipes](./http-recipes.md)** — typed clients, custom transports, production adoption, observability, and config validation
|
|
11
13
|
- **[Recipes](./recipes/README.md)** — copyable runtime, layer, HTTP server, testing, and performance paths
|
package/docs/ai/PUBLIC_API.md
CHANGED
|
@@ -234,6 +234,9 @@ Primary categories:
|
|
|
234
234
|
- production hardening helpers for exporter pipelines, sampling, redaction,
|
|
235
235
|
metric-cardinality limiting, environment presets, no-op setup, and inbound
|
|
236
236
|
adapters for Fetch/Node/Express/Fastify-style request objects
|
|
237
|
+
- `makeOtlpOptions` for turning a backend-neutral OTLP HTTP collector endpoint
|
|
238
|
+
into metrics/traces/logs URLs while forwarding headers, custom `fetch`,
|
|
239
|
+
timeout, retry, pipeline tuning, and optional signal selection
|
|
237
240
|
- OTLP log export, server-side HTTP request metrics/spans, span retention
|
|
238
241
|
pruning, single-flight flush behavior, collector smoke script, and
|
|
239
242
|
observability benchmark budgets
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Framework integrations
|
|
2
|
+
|
|
3
|
+
These recipes show how to wire Brass into common TypeScript application
|
|
4
|
+
frameworks without adding framework-specific dependencies to `brass-runtime`.
|
|
5
|
+
|
|
6
|
+
The common shape is:
|
|
7
|
+
|
|
8
|
+
- create one `Observability` instance near the application boundary;
|
|
9
|
+
- create one `Runtime` when framework handlers need to run effects;
|
|
10
|
+
- create one `makeDefaultHttpClient(...)` with `withHttpObservability(...)`;
|
|
11
|
+
- keep collector/vendor config in the application;
|
|
12
|
+
- shut down HTTP and observability queues from the host lifecycle when possible.
|
|
13
|
+
|
|
14
|
+
For browser apps, never expose Grafana Cloud tokens or collector secrets. Send
|
|
15
|
+
browser telemetry to a same-origin proxy such as `/api/otel`, then forward to
|
|
16
|
+
Grafana, Alloy, AppDynamics, or OpenTelemetry Collector from a trusted server.
|
|
17
|
+
|
|
18
|
+
## Recipes
|
|
19
|
+
|
|
20
|
+
| Framework | Recipe | Covers |
|
|
21
|
+
|-----------|--------|--------|
|
|
22
|
+
| Vanilla | [`docs/frameworks/vanilla.md`](./frameworks/vanilla.md) | Browser and Node setup without a framework |
|
|
23
|
+
| React | [`docs/frameworks/react.md`](./frameworks/react.md) | Context provider, hook, component usage |
|
|
24
|
+
| Next.js | [`docs/frameworks/nextjs.md`](./frameworks/nextjs.md) | App Router, server singleton, OTLP proxy |
|
|
25
|
+
| Angular | [`docs/frameworks/angular.md`](./frameworks/angular.md) | InjectionToken providers and services |
|
|
26
|
+
| Express | [`docs/frameworks/express.md`](./frameworks/express.md) | Request spans, `/metrics`, shutdown |
|
|
27
|
+
| Fastify | [`docs/frameworks/fastify.md`](./frameworks/fastify.md) | Request adapter, `/metrics`, shutdown |
|
|
28
|
+
| NestJS | [`docs/frameworks/nestjs.md`](./frameworks/nestjs.md) | Module providers, DI tokens, shutdown hooks |
|
|
29
|
+
|
|
30
|
+
Runnable dependency-optional examples live in:
|
|
31
|
+
|
|
32
|
+
- `src/examples/observabilityExpress.ts`
|
|
33
|
+
- `src/examples/observabilityFastify.ts`
|
|
34
|
+
- `src/examples/observabilityNest.ts`
|
|
35
|
+
|
|
36
|
+
See also [`docs/observability-framework-examples.md`](./observability-framework-examples.md)
|
|
37
|
+
for commands that run those examples locally.
|
|
38
|
+
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# Angular integration
|
|
2
|
+
|
|
3
|
+
Angular apps should expose Brass through `InjectionToken`s. Browser telemetry
|
|
4
|
+
should go to a same-origin proxy such as `/api/otel`; collector credentials
|
|
5
|
+
belong on the server side.
|
|
6
|
+
|
|
7
|
+
## Providers
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
// brass.providers.ts
|
|
11
|
+
import { inject, InjectionToken, type Provider } from "@angular/core";
|
|
12
|
+
import { Runtime } from "brass-runtime/core";
|
|
13
|
+
import {
|
|
14
|
+
defineHttpPolicyPresets,
|
|
15
|
+
makeDefaultHttpClient,
|
|
16
|
+
} from "brass-runtime/http";
|
|
17
|
+
import {
|
|
18
|
+
makeObservability,
|
|
19
|
+
makeOtlpOptions,
|
|
20
|
+
withHttpObservability,
|
|
21
|
+
} from "brass-runtime/observability";
|
|
22
|
+
|
|
23
|
+
const policyPresets = defineHttpPolicyPresets({
|
|
24
|
+
readModel: {
|
|
25
|
+
lane: "read-model",
|
|
26
|
+
priority: 3,
|
|
27
|
+
retry: { maxRetries: 2, baseDelayMs: 100, maxDelayMs: 1_000 },
|
|
28
|
+
},
|
|
29
|
+
command: {
|
|
30
|
+
lane: "command",
|
|
31
|
+
priority: 1,
|
|
32
|
+
retry: false,
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
function makeAngularBrass() {
|
|
37
|
+
const observability = makeObservability({
|
|
38
|
+
serviceName: "shop-angular",
|
|
39
|
+
resource: { "deployment.environment": "browser" },
|
|
40
|
+
logs: false,
|
|
41
|
+
sampling: { ratio: 0.1, respectRemoteSampled: true, forceSampleOnError: true },
|
|
42
|
+
redaction: {},
|
|
43
|
+
cardinality: { maxValuesPerLabel: 100 },
|
|
44
|
+
otlp: makeOtlpOptions({
|
|
45
|
+
endpoint: "/api/otel",
|
|
46
|
+
timeoutMs: 10_000,
|
|
47
|
+
retry: { attempts: 2, initialDelayMs: 100, maxDelayMs: 1_000 },
|
|
48
|
+
pipeline: { maxQueueSize: 2_000, batchSize: 128, dropPolicy: "drop-oldest" },
|
|
49
|
+
}),
|
|
50
|
+
flushIntervalMs: 15_000,
|
|
51
|
+
autoStart: true,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const runtime = new Runtime({
|
|
55
|
+
env: observability.env,
|
|
56
|
+
hooks: observability.hooks,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const http = makeDefaultHttpClient({
|
|
60
|
+
baseUrl: "/api",
|
|
61
|
+
preset: "balanced",
|
|
62
|
+
timeoutMs: 5_000,
|
|
63
|
+
policyPresets,
|
|
64
|
+
middleware: [withHttpObservability(observability)],
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
observability,
|
|
69
|
+
runtime,
|
|
70
|
+
http,
|
|
71
|
+
shutdown: async () => {
|
|
72
|
+
await http.shutdown();
|
|
73
|
+
await observability.shutdown();
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export const BRASS = new InjectionToken<ReturnType<typeof makeAngularBrass>>("BRASS");
|
|
79
|
+
|
|
80
|
+
export function provideBrass(): Provider[] {
|
|
81
|
+
return [
|
|
82
|
+
{
|
|
83
|
+
provide: BRASS,
|
|
84
|
+
useFactory: () => makeAngularBrass(),
|
|
85
|
+
},
|
|
86
|
+
];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function injectBrass() {
|
|
90
|
+
return inject(BRASS);
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Register the provider:
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
// app.config.ts
|
|
98
|
+
import { type ApplicationConfig } from "@angular/core";
|
|
99
|
+
import { provideBrass } from "./brass.providers";
|
|
100
|
+
|
|
101
|
+
export const appConfig: ApplicationConfig = {
|
|
102
|
+
providers: [
|
|
103
|
+
...provideBrass(),
|
|
104
|
+
],
|
|
105
|
+
};
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Service Usage
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
// users.service.ts
|
|
112
|
+
import { Injectable } from "@angular/core";
|
|
113
|
+
import { injectBrass } from "./brass.providers";
|
|
114
|
+
|
|
115
|
+
type User = {
|
|
116
|
+
readonly id: string;
|
|
117
|
+
readonly name: string;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
@Injectable({ providedIn: "root" })
|
|
121
|
+
export class UsersService {
|
|
122
|
+
private readonly brass = injectBrass();
|
|
123
|
+
|
|
124
|
+
getUser(id: string): Promise<User> {
|
|
125
|
+
return this.brass.runtime
|
|
126
|
+
.toPromise(
|
|
127
|
+
this.brass.http.getJson<User>(`/users/${id}`, {
|
|
128
|
+
policy: "readModel",
|
|
129
|
+
timeoutMs: 2_000,
|
|
130
|
+
}),
|
|
131
|
+
)
|
|
132
|
+
.then((response) => response.body);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Shutdown
|
|
138
|
+
|
|
139
|
+
Browser apps often do not have a reliable shutdown hook, but you can flush on
|
|
140
|
+
page lifecycle events:
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
import { injectBrass } from "./brass.providers";
|
|
144
|
+
|
|
145
|
+
export function installBrassBrowserShutdown() {
|
|
146
|
+
const brass = injectBrass();
|
|
147
|
+
|
|
148
|
+
window.addEventListener("pagehide", () => {
|
|
149
|
+
void brass.shutdown();
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Express integration
|
|
2
|
+
|
|
3
|
+
Express can wire Brass directly at process startup: one observability instance,
|
|
4
|
+
one runtime, one HTTP client, and a shutdown handler.
|
|
5
|
+
|
|
6
|
+
## App Setup
|
|
7
|
+
|
|
8
|
+
```ts
|
|
9
|
+
import express from "express";
|
|
10
|
+
import { asyncFlatMap } from "brass-runtime/core";
|
|
11
|
+
import {
|
|
12
|
+
defineHttpPolicyPresets,
|
|
13
|
+
makeDefaultHttpClient,
|
|
14
|
+
} from "brass-runtime/http";
|
|
15
|
+
import {
|
|
16
|
+
logEffect,
|
|
17
|
+
makeExpressRequestObservabilityContext,
|
|
18
|
+
makeObservability,
|
|
19
|
+
makeOtlpOptions,
|
|
20
|
+
withHttpObservability,
|
|
21
|
+
} from "brass-runtime/observability";
|
|
22
|
+
|
|
23
|
+
const policyPresets = defineHttpPolicyPresets({
|
|
24
|
+
readModel: {
|
|
25
|
+
lane: "read-model",
|
|
26
|
+
priority: 3,
|
|
27
|
+
retry: { maxRetries: 2, baseDelayMs: 100, maxDelayMs: 1_000 },
|
|
28
|
+
},
|
|
29
|
+
command: {
|
|
30
|
+
lane: "command",
|
|
31
|
+
priority: 1,
|
|
32
|
+
retry: false,
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const observability = makeObservability({
|
|
37
|
+
serviceName: process.env.OTEL_SERVICE_NAME ?? "shop-express",
|
|
38
|
+
serviceVersion: process.env.OTEL_SERVICE_VERSION,
|
|
39
|
+
resource: {
|
|
40
|
+
"deployment.environment": process.env.NODE_ENV ?? "development",
|
|
41
|
+
},
|
|
42
|
+
logs: { minLevel: "info" },
|
|
43
|
+
sampling: { ratio: 0.25, respectRemoteSampled: true, forceSampleOnError: true },
|
|
44
|
+
redaction: {},
|
|
45
|
+
cardinality: { maxValuesPerLabel: 100 },
|
|
46
|
+
otlp: makeOtlpOptions({
|
|
47
|
+
endpoint: process.env.GRAFANA_OTLP_ENDPOINT ?? "http://grafana-alloy:4318",
|
|
48
|
+
headers: process.env.GRAFANA_OTLP_AUTHORIZATION
|
|
49
|
+
? { Authorization: process.env.GRAFANA_OTLP_AUTHORIZATION }
|
|
50
|
+
: undefined,
|
|
51
|
+
timeoutMs: 10_000,
|
|
52
|
+
retry: { attempts: 3, initialDelayMs: 100, maxDelayMs: 2_000 },
|
|
53
|
+
pipeline: {
|
|
54
|
+
maxQueueSize: 10_000,
|
|
55
|
+
batchSize: 512,
|
|
56
|
+
dropPolicy: "drop-oldest",
|
|
57
|
+
shutdownTimeoutMs: 10_000,
|
|
58
|
+
},
|
|
59
|
+
}),
|
|
60
|
+
flushIntervalMs: 10_000,
|
|
61
|
+
autoStart: true,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const http = makeDefaultHttpClient({
|
|
65
|
+
baseUrl: process.env.USERS_API_BASE_URL ?? "https://users-api.internal",
|
|
66
|
+
preset: "production",
|
|
67
|
+
timeoutMs: 5_000,
|
|
68
|
+
policyPresets,
|
|
69
|
+
middleware: [withHttpObservability(observability)],
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const app = express();
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Routes
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
app.get("/users/:id", async (req, res, next) => {
|
|
79
|
+
const ctx = makeExpressRequestObservabilityContext(observability, req, {
|
|
80
|
+
route: "/users/:id",
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
const response = await ctx.run(
|
|
85
|
+
ctx.withRequestSpan(
|
|
86
|
+
asyncFlatMap(
|
|
87
|
+
logEffect("info", "users.lookup", {
|
|
88
|
+
userId: req.params.id,
|
|
89
|
+
authorization: req.headers.authorization,
|
|
90
|
+
}),
|
|
91
|
+
() =>
|
|
92
|
+
http.getJson(`/users/${req.params.id}`, {
|
|
93
|
+
policy: "readModel",
|
|
94
|
+
timeoutMs: 2_000,
|
|
95
|
+
}),
|
|
96
|
+
),
|
|
97
|
+
),
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
res.json(response.body);
|
|
101
|
+
} catch (error) {
|
|
102
|
+
next(error);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
app.get("/metrics", (_req, res) => {
|
|
107
|
+
res
|
|
108
|
+
.type(observability.prometheus.contentType)
|
|
109
|
+
.send(observability.prometheus.export());
|
|
110
|
+
});
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Shutdown
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
const server = app.listen(process.env.PORT ?? 3000);
|
|
117
|
+
|
|
118
|
+
process.once("SIGTERM", async () => {
|
|
119
|
+
await new Promise<void>((resolve) => server.close(() => resolve()));
|
|
120
|
+
await http.shutdown();
|
|
121
|
+
await observability.shutdown();
|
|
122
|
+
});
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Runnable repo example: `src/examples/observabilityExpress.ts`.
|