@capxul/observability 4.20.0-beta.4 → 4.20.0-beta.40
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 +96 -0
- package/dist/devtools.d.mts +7 -0
- package/dist/devtools.mjs +72 -0
- package/dist/engineering.d.mts +31 -16
- package/dist/engineering.mjs +520 -304
- package/dist/index.d.mts +31007 -3491
- package/dist/index.mjs +2 -2
- package/dist/src-CyMiJfOK.mjs +10868 -0
- package/package.json +18 -10
- package/dist/src-CyMef9yy.mjs +0 -3078
package/README.md
CHANGED
|
@@ -11,8 +11,101 @@ Activity action events accept the implemented `unresolved` Payment status in
|
|
|
11
11
|
committed filters and export filters. The event records the selected status;
|
|
12
12
|
it does not infer settlement from an unresolved result.
|
|
13
13
|
|
|
14
|
+
## Where things live
|
|
15
|
+
|
|
16
|
+
`src/index.ts` is the package door (`@capxul/observability`) and re-exports the
|
|
17
|
+
folders below. `src/engineering.ts` is the engineering subpath
|
|
18
|
+
(`@capxul/observability/engineering`): it builds the engineering telemetry Layer
|
|
19
|
+
from `engineering/` and `engineering-delivery.ts`.
|
|
20
|
+
|
|
21
|
+
| Folder | Owns |
|
|
22
|
+
| -------------- | --------------------------------------------------------------------------------------------------------------- |
|
|
23
|
+
| `catalog/` | Event names, journeys, the required envelope, bounded value schemas, every event's schema, CLI vocabularies. |
|
|
24
|
+
| `events/` | Event schemas by domain: identity, onboarding, organizations, money, chain, indexing, workflows, activity, CLI. |
|
|
25
|
+
| `operations/` | Operation names by concept group, composed with the protocol's rows in `operations.ts`. |
|
|
26
|
+
| `telemetry/` | The track handler, redaction before an event leaves the process, and in-process adapters. |
|
|
27
|
+
| `browser/` | Browser PostHog setup, event sanitizing and captured-network masking. |
|
|
28
|
+
| `engineering/` | Engineering logs, metrics and traces: configuration, serialization and the tracer. |
|
|
29
|
+
| `delivery/` | One CLI invocation's engineering delivery: admission, budget, records and export requests. |
|
|
30
|
+
|
|
31
|
+
`packages/tools/src/modules/lint/internal/telemetry-spine/` reads the catalog across `catalog/`,
|
|
32
|
+
`events/`, `telemetry/` and `browser/`, and treats every one of those files as
|
|
33
|
+
naming events rather than producing them.
|
|
34
|
+
|
|
35
|
+
```text
|
|
36
|
+
src/
|
|
37
|
+
├── devtools.ts
|
|
38
|
+
├── engineering-delivery.ts
|
|
39
|
+
├── engineering.ts
|
|
40
|
+
├── index.ts
|
|
41
|
+
├── operations.ts
|
|
42
|
+
├── telemetry-port.ts
|
|
43
|
+
├── __tests__/
|
|
44
|
+
│ ├── engineering-delivery.test.ts
|
|
45
|
+
│ ├── devtools.test.ts
|
|
46
|
+
│ ├── engineering.test.ts
|
|
47
|
+
│ ├── operations.test.ts
|
|
48
|
+
│ ├── posthog-browser-privacy.test.ts
|
|
49
|
+
│ └── telemetry.test.ts
|
|
50
|
+
├── browser/
|
|
51
|
+
│ ├── analytics.ts
|
|
52
|
+
│ ├── network.ts
|
|
53
|
+
│ └── sanitize.ts
|
|
54
|
+
├── catalog/
|
|
55
|
+
│ ├── cli.ts
|
|
56
|
+
│ ├── envelope.ts
|
|
57
|
+
│ ├── events.ts
|
|
58
|
+
│ ├── journeys.ts
|
|
59
|
+
│ ├── schemas.ts
|
|
60
|
+
│ └── values.ts
|
|
61
|
+
├── delivery/
|
|
62
|
+
│ ├── admission.ts
|
|
63
|
+
│ ├── budget.ts
|
|
64
|
+
│ ├── records.ts
|
|
65
|
+
│ └── requests.ts
|
|
66
|
+
├── engineering/
|
|
67
|
+
│ ├── config.ts
|
|
68
|
+
│ ├── logs.ts
|
|
69
|
+
│ ├── metric-points.ts
|
|
70
|
+
│ ├── minimal.ts
|
|
71
|
+
│ ├── serialization.ts
|
|
72
|
+
│ └── tracer.ts
|
|
73
|
+
├── events/
|
|
74
|
+
│ ├── activity.ts
|
|
75
|
+
│ ├── chain.ts
|
|
76
|
+
│ ├── cli.ts
|
|
77
|
+
│ ├── identity.ts
|
|
78
|
+
│ ├── indexing.ts
|
|
79
|
+
│ ├── money.ts
|
|
80
|
+
│ ├── onboarding.ts
|
|
81
|
+
│ ├── organizations.ts
|
|
82
|
+
│ └── workflows.ts
|
|
83
|
+
├── operations/
|
|
84
|
+
│ ├── money.ts
|
|
85
|
+
│ ├── organizations.ts
|
|
86
|
+
│ ├── people.ts
|
|
87
|
+
│ ├── platform.ts
|
|
88
|
+
│ └── tree.ts
|
|
89
|
+
└── telemetry/
|
|
90
|
+
├── adapters.ts
|
|
91
|
+
├── redaction.ts
|
|
92
|
+
└── track.ts
|
|
93
|
+
```
|
|
94
|
+
|
|
14
95
|
## The required envelope (ADR-0020 A1 amendment)
|
|
15
96
|
|
|
97
|
+
The `@capxul/observability/devtools` subpath exports `withDevTools(layer, url)` and
|
|
98
|
+
`validateDevToolsUrl(url)` for local Effect inspection. An omitted URL keeps the
|
|
99
|
+
original layer. An explicit local WebSocket URL adds the native Effect 4
|
|
100
|
+
DevTools connection after the host's services and metric registry are built.
|
|
101
|
+
The connection closes with the host scope. Local spans retain their original
|
|
102
|
+
detail; existing remote exporters keep their own privacy policy. The local
|
|
103
|
+
tracer does not mutate the remote exporter's span methods. Its optional protocol
|
|
104
|
+
loads only when enabled. The separate entry stays out of Convex's static runtime graph.
|
|
105
|
+
|
|
106
|
+
See [the development workflow](../../docs/canon/development-and-verification.md#local-effect-devtools)
|
|
107
|
+
for the editor and agent collector commands.
|
|
108
|
+
|
|
16
109
|
One PostHog project holds every environment, so `capxul_env` — not project
|
|
17
110
|
isolation — is what keeps a production surface from reading dev traffic. It is
|
|
18
111
|
REQUIRED on every catalog event, together with `producer`. Call sites do not
|
|
@@ -108,3 +201,6 @@ Set `privacy: "minimal"` for hosts that must export only closed operation/error
|
|
|
108
201
|
codes, timings, environment, and validated correlation. This opt-in removes
|
|
109
202
|
free-form logs, provider messages, URLs, bodies, and source paths, including
|
|
110
203
|
span exception events. Default consumers retain the existing redaction policy.
|
|
204
|
+
`minimalCorrelationId` is that projection's correlation rule: a host that shows
|
|
205
|
+
a correlation id to a person checks it first, so the id it shows is one the
|
|
206
|
+
export carries.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Layer } from "effect";
|
|
2
|
+
//#region src/devtools.d.ts
|
|
3
|
+
/** Local inspection is an explicit host choice, independent of remote telemetry. */
|
|
4
|
+
export declare function validateDevToolsUrl(value: string): string;
|
|
5
|
+
/** Acquire after the host layer so traces and metrics use the same context. */
|
|
6
|
+
export declare function withDevTools<R, E, I>(layer: Layer.Layer<R, E, I>, url: string | undefined): Layer.Layer<R, E, I>;
|
|
7
|
+
//#endregion
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Effect, Layer, Tracer } from "effect";
|
|
2
|
+
//#region src/devtools.ts
|
|
3
|
+
/** Local inspection is an explicit host choice, independent of remote telemetry. */
|
|
4
|
+
function validateDevToolsUrl(value) {
|
|
5
|
+
const url = new URL(value);
|
|
6
|
+
if (!["ws:", "wss:"].includes(url.protocol) || ![
|
|
7
|
+
"localhost",
|
|
8
|
+
"127.0.0.1",
|
|
9
|
+
"[::1]",
|
|
10
|
+
"host.docker.internal"
|
|
11
|
+
].includes(url.hostname) || url.username !== "" || url.password !== "" || url.search !== "" || url.hash !== "") throw new TypeError("devToolsUrl must be a local WebSocket URL without credentials");
|
|
12
|
+
return url.href;
|
|
13
|
+
}
|
|
14
|
+
function localSpan(delegate) {
|
|
15
|
+
const attributes = new Map(delegate.attributes);
|
|
16
|
+
let status = delegate.status;
|
|
17
|
+
return {
|
|
18
|
+
_tag: "Span",
|
|
19
|
+
name: delegate.name,
|
|
20
|
+
spanId: delegate.spanId,
|
|
21
|
+
traceId: delegate.traceId,
|
|
22
|
+
parent: delegate.parent,
|
|
23
|
+
annotations: delegate.annotations,
|
|
24
|
+
sampled: delegate.sampled,
|
|
25
|
+
kind: delegate.kind,
|
|
26
|
+
attributes,
|
|
27
|
+
get status() {
|
|
28
|
+
return status;
|
|
29
|
+
},
|
|
30
|
+
get links() {
|
|
31
|
+
return delegate.links;
|
|
32
|
+
},
|
|
33
|
+
attribute(key, value) {
|
|
34
|
+
attributes.set(key, value);
|
|
35
|
+
delegate.attribute(key, value);
|
|
36
|
+
},
|
|
37
|
+
event(name, time, values) {
|
|
38
|
+
delegate.event(name, time, values);
|
|
39
|
+
},
|
|
40
|
+
addLinks(links) {
|
|
41
|
+
delegate.addLinks(links);
|
|
42
|
+
},
|
|
43
|
+
end(endTime, exit) {
|
|
44
|
+
delegate.end(endTime, exit);
|
|
45
|
+
status = {
|
|
46
|
+
_tag: "Ended",
|
|
47
|
+
startTime: status.startTime,
|
|
48
|
+
endTime,
|
|
49
|
+
exit
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/** Acquire after the host layer so traces and metrics use the same context. */
|
|
55
|
+
function withDevTools(layer, url) {
|
|
56
|
+
if (url === void 0) return layer;
|
|
57
|
+
const endpoint = validateDevToolsUrl(url);
|
|
58
|
+
return Layer.unwrap(Effect.promise(async () => {
|
|
59
|
+
const [{ DevToolsClient }, { Socket }] = await Promise.all([import("effect/devtools"), import("effect/socket")]);
|
|
60
|
+
const client = DevToolsClient.layer.pipe(Layer.provide(Socket.layerWebSocket(endpoint)), Layer.provide(Socket.layerWebSocketConstructorGlobal));
|
|
61
|
+
return Layer.effect(Tracer.Tracer, Effect.gen(function* () {
|
|
62
|
+
const delegate = yield* Effect.tracer;
|
|
63
|
+
const mirror = Tracer.make({
|
|
64
|
+
span: (options) => localSpan(delegate.span(options)),
|
|
65
|
+
...delegate.context === void 0 ? {} : { context: delegate.context.bind(delegate) }
|
|
66
|
+
});
|
|
67
|
+
return yield* DevToolsClient.makeTracer.pipe(Effect.provideService(Tracer.Tracer, mirror));
|
|
68
|
+
})).pipe(Layer.provide(client), Layer.provideMerge(layer));
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
71
|
+
//#endregion
|
|
72
|
+
export { validateDevToolsUrl, withDevTools };
|
package/dist/engineering.d.mts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { Context, Duration, Effect, Layer, Logger, Metric,
|
|
2
|
-
import { HttpClient
|
|
3
|
-
import { OtlpExporter
|
|
4
|
-
//#region src/
|
|
1
|
+
import { Context, Duration, Effect, Layer, Logger, Metric, Tracer } from "effect";
|
|
2
|
+
import { HttpClient } from "effect/http";
|
|
3
|
+
import { OtlpExporter } from "effect/observability";
|
|
4
|
+
//#region src/delivery/budget.d.ts
|
|
5
5
|
/** Fixed admission limits for one CLI invocation and its SDK client. */
|
|
6
|
-
declare const CLI_ENGINEERING_LIMITS: Readonly<{
|
|
6
|
+
export declare const CLI_ENGINEERING_LIMITS: Readonly<{
|
|
7
7
|
records: 80;
|
|
8
8
|
ordinaryRecords: 64;
|
|
9
9
|
recordBytes: 16384;
|
|
10
|
+
recordFields: 48;
|
|
10
11
|
requests: 5;
|
|
11
12
|
ordinaryRequests: 2;
|
|
12
13
|
requestBytes: 1572864;
|
|
@@ -28,7 +29,7 @@ interface CliEngineeringStats {
|
|
|
28
29
|
readonly metricSeries: number;
|
|
29
30
|
}
|
|
30
31
|
/** Shared, closure-owned admission state; no queue or mutable counters are exposed. */
|
|
31
|
-
declare function makeCliEngineeringBudget(): Readonly<{
|
|
32
|
+
export declare function makeCliEngineeringBudget(): Readonly<{
|
|
32
33
|
metricRegistry: Map<string, MetricEntry>;
|
|
33
34
|
emptyMetricRegistry: () => Map<string, MetricEntry>;
|
|
34
35
|
drop: () => void;
|
|
@@ -38,9 +39,9 @@ declare function makeCliEngineeringBudget(): Readonly<{
|
|
|
38
39
|
}>;
|
|
39
40
|
type CliEngineeringBudget = ReturnType<typeof makeCliEngineeringBudget>;
|
|
40
41
|
//#endregion
|
|
41
|
-
//#region src/engineering.d.ts
|
|
42
|
+
//#region src/engineering/config.d.ts
|
|
42
43
|
type EngineeringProducer = "browser" | "server";
|
|
43
|
-
declare const ENGINEERING_CAPXUL_ENVS: readonly ["development", "staging", "production", "local"];
|
|
44
|
+
export declare const ENGINEERING_CAPXUL_ENVS: readonly ["development", "staging", "production", "local"];
|
|
44
45
|
type EngineeringCapxulEnv = (typeof ENGINEERING_CAPXUL_ENVS)[number];
|
|
45
46
|
interface EngineeringTelemetryConfig {
|
|
46
47
|
readonly host: string;
|
|
@@ -58,21 +59,35 @@ interface EngineeringTelemetryConfig {
|
|
|
58
59
|
/** CLI-only shared admission and transport lifetime. Omission preserves host defaults. */
|
|
59
60
|
readonly deliveryBudget?: CliEngineeringBudget;
|
|
60
61
|
}
|
|
61
|
-
declare const traceHeaderFilter: (_name: string) => boolean;
|
|
62
|
-
declare const postHogOtlpEndpoints: (host: string) => {
|
|
62
|
+
export declare const traceHeaderFilter: (_name: string) => boolean;
|
|
63
|
+
export declare const postHogOtlpEndpoints: (host: string) => {
|
|
63
64
|
readonly logs: `${string}/i/v1/logs`;
|
|
64
65
|
readonly traces: `${string}/i/v1/traces`;
|
|
65
66
|
readonly metrics: `${string}/i/v1/metrics`;
|
|
66
67
|
};
|
|
67
|
-
|
|
68
|
-
|
|
68
|
+
//#endregion
|
|
69
|
+
//#region src/engineering/logs.d.ts
|
|
69
70
|
/** Attempt to drain all engineering signals; completion does not prove ingestion. */
|
|
70
|
-
declare const flushEngineeringTelemetry: Effect.Effect<void, never, OtlpExporter.Flusher>;
|
|
71
|
+
export declare const flushEngineeringTelemetry: Effect.Effect<void, never, OtlpExporter.Flusher>;
|
|
71
72
|
declare const EngineeringLog_base: Context.ServiceClass<EngineeringLog, "capxul/EngineeringLog", Logger.Logger<unknown, void>>;
|
|
72
73
|
declare class EngineeringLog extends EngineeringLog_base {}
|
|
73
74
|
/** Deliver an owned engineering record without changing the caller's console verbosity. */
|
|
74
|
-
declare const logEngineeringInfo: (message: string, attributes: Readonly<Record<string, unknown>>) => Effect.Effect<void, never,
|
|
75
|
+
export declare const logEngineeringInfo: (message: string, attributes: Readonly<Record<string, unknown>>) => Effect.Effect<void, never, never>;
|
|
76
|
+
//#endregion
|
|
77
|
+
//#region src/engineering/tracer.d.ts
|
|
78
|
+
/** Preserve domain exits while preventing the OTLP serializer from seeing raw causes. */
|
|
79
|
+
export declare const makeLeakSafeEngineeringTracer: (delegate: Tracer.Tracer, enabled?: () => boolean) => Tracer.Tracer;
|
|
80
|
+
//#endregion
|
|
81
|
+
//#region src/engineering/minimal.d.ts
|
|
82
|
+
/**
|
|
83
|
+
* A correlation id the minimal export carries: an identifier with no `/`, not
|
|
84
|
+
* `0x` hex, and unchanged by the secret mask. The CLI quotes a backend
|
|
85
|
+
* correlation id as its `ref` only when it passes, so the ref finds a row.
|
|
86
|
+
*/
|
|
87
|
+
export declare const minimalCorrelationId: (value: unknown) => value is string;
|
|
88
|
+
//#endregion
|
|
89
|
+
//#region src/engineering.d.ts
|
|
75
90
|
/** Shared browser/server OTLP layer. OtlpLogger merges with incumbent loggers once. */
|
|
76
|
-
declare const makeEngineeringTelemetryLayer: (config: EngineeringTelemetryConfig) => Layer.Layer<EngineeringLog | OtlpExporter.Flusher, never, never>;
|
|
91
|
+
export declare const makeEngineeringTelemetryLayer: (config: EngineeringTelemetryConfig) => Layer.Layer<EngineeringLog | OtlpExporter.Flusher, never, never>;
|
|
77
92
|
//#endregion
|
|
78
|
-
export {
|
|
93
|
+
export type { CliEngineeringBudget, CliEngineeringStats, EngineeringCapxulEnv, EngineeringProducer, EngineeringTelemetryConfig };
|