@qlever-llc/trellis 0.10.11 → 0.10.12
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/esm/errors/TrellisError.d.ts +3 -3
- package/esm/errors/TrellisError.js +3 -3
- package/esm/server/internal_jobs/job-manager.d.ts.map +1 -1
- package/esm/server/internal_jobs/job-manager.js +32 -1
- package/esm/server/runtime.d.ts +3 -0
- package/esm/server/runtime.d.ts.map +1 -1
- package/esm/server/service.d.ts +15 -0
- package/esm/server/service.d.ts.map +1 -1
- package/esm/server/service.js +8 -0
- package/esm/server.d.ts.map +1 -1
- package/esm/server.js +54 -6
- package/esm/service/deno.d.ts +1 -1
- package/esm/service/deno.d.ts.map +1 -1
- package/esm/service/mod.d.ts +1 -1
- package/esm/service/mod.d.ts.map +1 -1
- package/esm/service/node.d.ts +1 -1
- package/esm/service/node.d.ts.map +1 -1
- package/esm/service/outbox_inbox.d.ts.map +1 -1
- package/esm/service/outbox_inbox.js +14 -0
- package/esm/telemetry/core.d.ts.map +1 -1
- package/esm/telemetry/core.js +1 -1
- package/esm/telemetry/env.d.ts.map +1 -1
- package/esm/telemetry/env.js +6 -1
- package/esm/telemetry/init.d.ts +3 -0
- package/esm/telemetry/init.d.ts.map +1 -0
- package/esm/telemetry/init.js +7 -0
- package/esm/telemetry/metrics.d.ts +34 -0
- package/esm/telemetry/metrics.d.ts.map +1 -0
- package/esm/telemetry/metrics.js +181 -0
- package/esm/telemetry/mod.d.ts +3 -0
- package/esm/telemetry/mod.d.ts.map +1 -1
- package/esm/telemetry/mod.js +2 -0
- package/esm/telemetry/runtime.d.ts +2 -0
- package/esm/telemetry/runtime.d.ts.map +1 -0
- package/esm/telemetry/runtime.js +134 -0
- package/esm/telemetry.d.ts +3 -0
- package/esm/telemetry.d.ts.map +1 -0
- package/esm/telemetry.js +2 -0
- package/esm/transfer.d.ts.map +1 -1
- package/esm/transfer.js +27 -16
- package/esm/trellis.d.ts.map +1 -1
- package/esm/trellis.js +460 -56
- package/package.json +7 -5
- package/script/errors/TrellisError.d.ts +3 -3
- package/script/errors/TrellisError.js +3 -3
- package/script/server/internal_jobs/job-manager.d.ts.map +1 -1
- package/script/server/internal_jobs/job-manager.js +32 -1
- package/script/server/runtime.d.ts +3 -0
- package/script/server/runtime.d.ts.map +1 -1
- package/script/server/service.d.ts +15 -0
- package/script/server/service.d.ts.map +1 -1
- package/script/server/service.js +8 -0
- package/script/server.d.ts.map +1 -1
- package/script/server.js +54 -6
- package/script/service/deno.d.ts +1 -1
- package/script/service/deno.d.ts.map +1 -1
- package/script/service/mod.d.ts +1 -1
- package/script/service/mod.d.ts.map +1 -1
- package/script/service/node.d.ts +1 -1
- package/script/service/node.d.ts.map +1 -1
- package/script/service/outbox_inbox.d.ts.map +1 -1
- package/script/service/outbox_inbox.js +14 -0
- package/script/telemetry/core.d.ts.map +1 -1
- package/script/telemetry/core.js +1 -1
- package/script/telemetry/env.d.ts.map +1 -1
- package/script/telemetry/env.js +6 -1
- package/script/telemetry/init.d.ts +3 -0
- package/script/telemetry/init.d.ts.map +1 -0
- package/script/telemetry/init.js +10 -0
- package/script/telemetry/metrics.d.ts +34 -0
- package/script/telemetry/metrics.d.ts.map +1 -0
- package/script/telemetry/metrics.js +186 -0
- package/script/telemetry/mod.d.ts +3 -0
- package/script/telemetry/mod.d.ts.map +1 -1
- package/script/telemetry/mod.js +7 -1
- package/script/telemetry/runtime.d.ts +2 -0
- package/script/telemetry/runtime.d.ts.map +1 -0
- package/script/telemetry/runtime.js +137 -0
- package/script/telemetry.d.ts +3 -0
- package/script/telemetry.d.ts.map +1 -0
- package/script/telemetry.js +18 -0
- package/script/transfer.d.ts.map +1 -1
- package/script/transfer.js +28 -17
- package/script/trellis.d.ts.map +1 -1
- package/script/trellis.js +490 -86
- package/src/errors/TrellisError.ts +4 -4
- package/src/server/internal_jobs/job-manager.ts +35 -5
- package/src/server/runtime.ts +4 -0
- package/src/server/service.ts +27 -0
- package/src/server.ts +66 -11
- package/src/service/deno.ts +1 -0
- package/src/service/mod.ts +1 -0
- package/src/service/node.ts +1 -0
- package/src/service/outbox_inbox.ts +14 -0
- package/src/telemetry/core.ts +1 -1
- package/src/telemetry/env.ts +5 -1
- package/src/telemetry/init.ts +8 -0
- package/src/telemetry/metrics.ts +294 -0
- package/src/telemetry/mod.ts +7 -0
- package/src/telemetry/runtime.ts +218 -0
- package/src/telemetry.ts +2 -0
- package/src/transfer.ts +69 -30
- package/src/trellis.ts +487 -88
- package/esm/tracing.d.ts +0 -5
- package/esm/tracing.d.ts.map +0 -1
- package/esm/tracing.js +0 -8
- package/script/tracing.d.ts +0 -5
- package/script/tracing.d.ts.map +0 -1
- package/script/tracing.js +0 -27
- package/src/tracing.ts +0 -28
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/telemetry/core.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EACZ,OAAO,EACP,KAAK,IAAI,EACT,QAAQ,EACR,cAAc,EACd,KAAK,EACL,KAAK,MAAM,EACZ,MAAM,oBAAoB,CAAC;AAE5B,wBAAgB,SAAS,CAAC,KAAK,
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/telemetry/core.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EACZ,OAAO,EACP,KAAK,IAAI,EACT,QAAQ,EACR,cAAc,EACd,KAAK,EACL,KAAK,MAAM,EACZ,MAAM,oBAAoB,CAAC;AAE5B,wBAAgB,SAAS,CAAC,KAAK,SAAkC,GAAG,MAAM,CAEzE;AAED,wBAAgB,aAAa,IAAI,IAAI,GAAG,SAAS,CAEhD;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAEtD;AAED,wBAAsB,aAAa,CAAC,CAAC,EACnC,IAAI,EAAE,IAAI,EACV,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACnB,OAAO,CAAC,CAAC,CAAC,CAEZ;AAED,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC;AACpD,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC"}
|
package/esm/telemetry/core.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { context, SpanKind, SpanStatusCode, trace, } from "@opentelemetry/api";
|
|
2
|
-
export function getTracer(scope = "@qlever-llc/trellis/
|
|
2
|
+
export function getTracer(scope = "@qlever-llc/trellis/telemetry") {
|
|
3
3
|
return trace.getTracer(scope);
|
|
4
4
|
}
|
|
5
5
|
export function getActiveSpan() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/telemetry/env.ts"],"names":[],"mappings":"AAYA,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/telemetry/env.ts"],"names":[],"mappings":"AAYA,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CActD"}
|
package/esm/telemetry/env.js
CHANGED
|
@@ -3,7 +3,12 @@ import * as dntShim from "../_dnt.shims.js";
|
|
|
3
3
|
export function getEnv(key) {
|
|
4
4
|
const deno = dntShim.dntGlobalThis;
|
|
5
5
|
if (deno.Deno?.env?.get) {
|
|
6
|
-
|
|
6
|
+
try {
|
|
7
|
+
return deno.Deno.env.get(key);
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
7
12
|
}
|
|
8
13
|
const processGlobal = dntShim.dntGlobalThis;
|
|
9
14
|
return processGlobal.process?.env?.[key];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/telemetry/init.ts"],"names":[],"mappings":"AAGA,2DAA2D;AAC3D,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAGvD"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { configureErrorTraceId } from "./result.js";
|
|
2
|
+
import { initTelemetryRuntime } from "./runtime.js";
|
|
3
|
+
/** Initializes Trellis telemetry for a service runtime. */
|
|
4
|
+
export function initTelemetry(serviceName) {
|
|
5
|
+
configureErrorTraceId();
|
|
6
|
+
initTelemetryRuntime(serviceName);
|
|
7
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type Meter } from "@opentelemetry/api";
|
|
2
|
+
/** Low-cardinality attributes accepted by {@link recordTrellisError}. */
|
|
3
|
+
export type TrellisErrorMetricAttributes = {
|
|
4
|
+
/** Stable Trellis surface name, such as `rpc`, `jobs`, or `operations`. */
|
|
5
|
+
surface?: string;
|
|
6
|
+
/** Stable flow direction such as `client`, `server`, `publish`, or `consume`. */
|
|
7
|
+
direction?: string;
|
|
8
|
+
/** Stable operation kind or method name. Do not pass IDs, subjects, or URLs. */
|
|
9
|
+
operation?: string;
|
|
10
|
+
/** Stable lifecycle phase such as `encode`, `send`, `auth`, or `handler`. */
|
|
11
|
+
phase?: string;
|
|
12
|
+
/** Stable local Trellis error type override when the thrown value does not expose one. */
|
|
13
|
+
errorType?: string;
|
|
14
|
+
/** Stable wrapped remote Trellis error type override. */
|
|
15
|
+
remoteErrorType?: string;
|
|
16
|
+
/** Stable auth failure reason, such as `missing_session_key`. */
|
|
17
|
+
authReason?: string;
|
|
18
|
+
/** Static messaging system name, when already known. */
|
|
19
|
+
messagingSystem?: string;
|
|
20
|
+
/** Static messaging operation name, when already known. */
|
|
21
|
+
messagingOperation?: string;
|
|
22
|
+
};
|
|
23
|
+
/** Returns the shared Trellis OpenTelemetry meter. */
|
|
24
|
+
export declare function getTrellisMeter(): Meter;
|
|
25
|
+
/** Records one Trellis error with only stable, low-cardinality attributes. */
|
|
26
|
+
export declare function recordTrellisError(error: unknown, attributes?: TrellisErrorMetricAttributes): void;
|
|
27
|
+
/**
|
|
28
|
+
* Builds sanitized, low-cardinality attributes for `trellis.errors`.
|
|
29
|
+
*
|
|
30
|
+
* @internal Exported for focused tests; runtime callers should use
|
|
31
|
+
* {@link recordTrellisError}.
|
|
32
|
+
*/
|
|
33
|
+
export declare function buildTrellisErrorMetricAttributes(error: unknown, attributes?: TrellisErrorMetricAttributes): Record<string, string>;
|
|
34
|
+
//# sourceMappingURL=metrics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../src/telemetry/metrics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,KAAK,EAAW,MAAM,oBAAoB,CAAC;AAiDzD,yEAAyE;AACzE,MAAM,MAAM,4BAA4B,GAAG;IACzC,2EAA2E;IAC3E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gFAAgF;IAChF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0FAA0F;IAC1F,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iEAAiE;IACjE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wDAAwD;IACxD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,2DAA2D;IAC3D,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B,CAAC;AASF,sDAAsD;AACtD,wBAAgB,eAAe,IAAI,KAAK,CAEvC;AAED,8EAA8E;AAC9E,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,OAAO,EACd,UAAU,GAAE,4BAAiC,GAC5C,IAAI,CAWN;AAED;;;;;GAKG;AACH,wBAAgB,iCAAiC,CAC/C,KAAK,EAAE,OAAO,EACd,UAAU,GAAE,4BAAiC,GAC5C,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAsDxB"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { metrics } from "@opentelemetry/api";
|
|
2
|
+
const TRELLIS_METER_NAME = "@qlever-llc/trellis";
|
|
3
|
+
const MAX_ATTRIBUTE_LENGTH = 96;
|
|
4
|
+
const LOW_CARDINALITY_PATTERN = /^[A-Za-z0-9_.:-]+$/;
|
|
5
|
+
const UUID_PATTERN = /(^|[_.:-])[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}($|[_.:-])/i;
|
|
6
|
+
const ULID_PATTERN = /(^|[_.:-])[0-7][0-9A-HJKMNP-TV-Z]{25}($|[_.:-])/i;
|
|
7
|
+
const LONG_HEX_SEGMENT_PATTERN = /(^|[_.:-])[0-9a-f]{12,}($|[_.:-])/i;
|
|
8
|
+
const TRELLIS_SUBJECT_PREFIX_PATTERN = /^(rpc|events|feeds|operations|jobs|state|kv|store|resources|transfer)\.v\d+\./;
|
|
9
|
+
const AUTH_REASONS = new Set([
|
|
10
|
+
"invalid_request",
|
|
11
|
+
"missing_session_key",
|
|
12
|
+
"missing_proof",
|
|
13
|
+
"session_not_found",
|
|
14
|
+
"session_expired",
|
|
15
|
+
"invalid_signature",
|
|
16
|
+
"user_not_found",
|
|
17
|
+
"user_already_exists",
|
|
18
|
+
"username_taken",
|
|
19
|
+
"identity_already_exists",
|
|
20
|
+
"identity_not_found",
|
|
21
|
+
"user_inactive",
|
|
22
|
+
"unknown_device",
|
|
23
|
+
"device_deployment_not_found",
|
|
24
|
+
"device_deployment_disabled",
|
|
25
|
+
"device_activation_revoked",
|
|
26
|
+
"unknown_service",
|
|
27
|
+
"service_disabled",
|
|
28
|
+
"iat_out_of_range",
|
|
29
|
+
"invalid_binding_token",
|
|
30
|
+
"session_corrupted",
|
|
31
|
+
"session_already_bound",
|
|
32
|
+
"authtoken_already_used",
|
|
33
|
+
"oauth_session_key_mismatch",
|
|
34
|
+
"reply_subject_mismatch",
|
|
35
|
+
"insufficient_permissions",
|
|
36
|
+
"forbidden",
|
|
37
|
+
"last_admin_required",
|
|
38
|
+
"missing_flow_id",
|
|
39
|
+
"device_activation_flow_not_found",
|
|
40
|
+
"device_activation_flow_expired",
|
|
41
|
+
"device_activation_rejected",
|
|
42
|
+
"device_identity_key_mismatch",
|
|
43
|
+
"invalid_device_qr_mac",
|
|
44
|
+
]);
|
|
45
|
+
/** Returns the shared Trellis OpenTelemetry meter. */
|
|
46
|
+
export function getTrellisMeter() {
|
|
47
|
+
return metrics.getMeter(TRELLIS_METER_NAME);
|
|
48
|
+
}
|
|
49
|
+
/** Records one Trellis error with only stable, low-cardinality attributes. */
|
|
50
|
+
export function recordTrellisError(error, attributes = {}) {
|
|
51
|
+
getTrellisMeter().createCounter("trellis.errors", {
|
|
52
|
+
description: "Trellis errors observed by runtime instrumentation.",
|
|
53
|
+
unit: "{error}",
|
|
54
|
+
}).add(1, buildTrellisErrorMetricAttributes(error, attributes));
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Builds sanitized, low-cardinality attributes for `trellis.errors`.
|
|
58
|
+
*
|
|
59
|
+
* @internal Exported for focused tests; runtime callers should use
|
|
60
|
+
* {@link recordTrellisError}.
|
|
61
|
+
*/
|
|
62
|
+
export function buildTrellisErrorMetricAttributes(error, attributes = {}) {
|
|
63
|
+
const serializable = serializableErrorData(error);
|
|
64
|
+
const metricAttributes = {
|
|
65
|
+
"exception.type": exceptionType(error),
|
|
66
|
+
"trellis.error.type": trellisErrorType(error, serializable, attributes.errorType),
|
|
67
|
+
};
|
|
68
|
+
const remoteErrorType = lowCardinalityValue(attributes.remoteErrorType) ??
|
|
69
|
+
remoteSerializableErrorType(serializable);
|
|
70
|
+
if (remoteErrorType) {
|
|
71
|
+
metricAttributes["trellis.remote_error.type"] = remoteErrorType;
|
|
72
|
+
}
|
|
73
|
+
setLowCardinalityAttribute(metricAttributes, "trellis.surface", attributes.surface);
|
|
74
|
+
setLowCardinalityAttribute(metricAttributes, "trellis.direction", attributes.direction);
|
|
75
|
+
setLowCardinalityAttribute(metricAttributes, "trellis.operation", attributes.operation);
|
|
76
|
+
setLowCardinalityAttribute(metricAttributes, "trellis.phase", attributes.phase);
|
|
77
|
+
setLowCardinalityAttribute(metricAttributes, "trellis.auth.reason", boundedAuthReason(attributes.authReason) ?? authReason(serializable));
|
|
78
|
+
setLowCardinalityAttribute(metricAttributes, "messaging.system", attributes.messagingSystem);
|
|
79
|
+
setLowCardinalityAttribute(metricAttributes, "messaging.operation", attributes.messagingOperation);
|
|
80
|
+
return metricAttributes;
|
|
81
|
+
}
|
|
82
|
+
function trellisErrorType(error, serializable, override) {
|
|
83
|
+
const overrideType = lowCardinalityValue(override);
|
|
84
|
+
if (overrideType)
|
|
85
|
+
return overrideType;
|
|
86
|
+
const serializableType = lowCardinalityValue(serializable?.type);
|
|
87
|
+
if (serializableType)
|
|
88
|
+
return serializableType;
|
|
89
|
+
const objectType = objectStringProperty(error, "type");
|
|
90
|
+
if (objectType)
|
|
91
|
+
return objectType;
|
|
92
|
+
return exceptionType(error);
|
|
93
|
+
}
|
|
94
|
+
function exceptionType(error) {
|
|
95
|
+
if (error instanceof Error) {
|
|
96
|
+
const name = lowCardinalityValue(error.name);
|
|
97
|
+
if (name)
|
|
98
|
+
return name;
|
|
99
|
+
}
|
|
100
|
+
const objectType = objectStringProperty(error, "type");
|
|
101
|
+
if (objectType)
|
|
102
|
+
return objectType;
|
|
103
|
+
return "unknown";
|
|
104
|
+
}
|
|
105
|
+
function serializableErrorData(error) {
|
|
106
|
+
const toSerializable = safeProperty(error, "toSerializable");
|
|
107
|
+
if (!isSerializableMethod(toSerializable))
|
|
108
|
+
return undefined;
|
|
109
|
+
try {
|
|
110
|
+
const data = toSerializable.call(error);
|
|
111
|
+
return isRecord(data) ? data : undefined;
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function remoteSerializableErrorType(serializable) {
|
|
118
|
+
const remoteError = safeProperty(serializable, "remoteError");
|
|
119
|
+
if (!isRecord(remoteError))
|
|
120
|
+
return undefined;
|
|
121
|
+
return objectStringProperty(remoteError, "type");
|
|
122
|
+
}
|
|
123
|
+
function authReason(serializable) {
|
|
124
|
+
const type = safeProperty(serializable, "type");
|
|
125
|
+
if (type === "AuthError") {
|
|
126
|
+
return boundedAuthReason(safeProperty(serializable, "reason"));
|
|
127
|
+
}
|
|
128
|
+
if (type === "RemoteError") {
|
|
129
|
+
const remoteError = safeProperty(serializable, "remoteError");
|
|
130
|
+
if (isRecord(remoteError) && objectStringProperty(remoteError, "type") ===
|
|
131
|
+
"AuthError") {
|
|
132
|
+
return boundedAuthReason(safeProperty(remoteError, "reason"));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return undefined;
|
|
136
|
+
}
|
|
137
|
+
function boundedAuthReason(value) {
|
|
138
|
+
const sanitized = lowCardinalityValue(value);
|
|
139
|
+
if (!sanitized || !AUTH_REASONS.has(sanitized))
|
|
140
|
+
return undefined;
|
|
141
|
+
return sanitized;
|
|
142
|
+
}
|
|
143
|
+
function isRecord(value) {
|
|
144
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
145
|
+
}
|
|
146
|
+
function isSerializableMethod(value) {
|
|
147
|
+
return typeof value === "function";
|
|
148
|
+
}
|
|
149
|
+
function safeProperty(value, key) {
|
|
150
|
+
if (!isRecord(value))
|
|
151
|
+
return undefined;
|
|
152
|
+
try {
|
|
153
|
+
return value[key];
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
return undefined;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function objectStringProperty(value, key) {
|
|
160
|
+
return lowCardinalityValue(safeProperty(value, key));
|
|
161
|
+
}
|
|
162
|
+
function setLowCardinalityAttribute(attributes, key, value) {
|
|
163
|
+
const sanitized = lowCardinalityValue(value);
|
|
164
|
+
if (sanitized)
|
|
165
|
+
attributes[key] = sanitized;
|
|
166
|
+
}
|
|
167
|
+
function lowCardinalityValue(value) {
|
|
168
|
+
if (typeof value !== "string")
|
|
169
|
+
return undefined;
|
|
170
|
+
const trimmed = value.trim();
|
|
171
|
+
if (trimmed.length === 0 ||
|
|
172
|
+
trimmed.length > MAX_ATTRIBUTE_LENGTH ||
|
|
173
|
+
!LOW_CARDINALITY_PATTERN.test(trimmed) ||
|
|
174
|
+
UUID_PATTERN.test(trimmed) ||
|
|
175
|
+
ULID_PATTERN.test(trimmed) ||
|
|
176
|
+
LONG_HEX_SEGMENT_PATTERN.test(trimmed) ||
|
|
177
|
+
TRELLIS_SUBJECT_PREFIX_PATTERN.test(trimmed)) {
|
|
178
|
+
return undefined;
|
|
179
|
+
}
|
|
180
|
+
return trimmed;
|
|
181
|
+
}
|
package/esm/telemetry/mod.d.ts
CHANGED
|
@@ -3,6 +3,9 @@ export { createMapCarrier, extractTraceContext, injectTraceContext, } from "./ca
|
|
|
3
3
|
export type { Context, Span } from "./core.js";
|
|
4
4
|
export { context, getActiveSpan, getTracer, SpanKind, SpanStatusCode, trace, withSpan, withSpanAsync, } from "./core.js";
|
|
5
5
|
export { getEnv } from "./env.js";
|
|
6
|
+
export { initTelemetry } from "./init.js";
|
|
7
|
+
export { buildTrellisErrorMetricAttributes, getTrellisMeter, recordTrellisError, } from "./metrics.js";
|
|
8
|
+
export type { TrellisErrorMetricAttributes } from "./metrics.js";
|
|
6
9
|
export type { NatsHeadersLike } from "./nats.js";
|
|
7
10
|
export { createNatsHeaderCarrier } from "./nats.js";
|
|
8
11
|
export { configureErrorTraceId } from "./result.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../src/telemetry/mod.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EACL,OAAO,EACP,aAAa,EACb,SAAS,EACT,QAAQ,EACR,cAAc,EACd,KAAK,EACL,QAAQ,EACR,aAAa,GACd,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,YAAY,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,eAAe,GAChB,MAAM,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../src/telemetry/mod.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EACL,OAAO,EACP,aAAa,EACb,SAAS,EACT,QAAQ,EACR,cAAc,EACd,KAAK,EACL,QAAQ,EACR,aAAa,GACd,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EACL,iCAAiC,EACjC,eAAe,EACf,kBAAkB,GACnB,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,4BAA4B,EAAE,MAAM,cAAc,CAAC;AACjE,YAAY,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,eAAe,GAChB,MAAM,cAAc,CAAC"}
|
package/esm/telemetry/mod.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export { createMapCarrier, extractTraceContext, injectTraceContext, } from "./carrier.js";
|
|
2
2
|
export { context, getActiveSpan, getTracer, SpanKind, SpanStatusCode, trace, withSpan, withSpanAsync, } from "./core.js";
|
|
3
3
|
export { getEnv } from "./env.js";
|
|
4
|
+
export { initTelemetry } from "./init.js";
|
|
5
|
+
export { buildTrellisErrorMetricAttributes, getTrellisMeter, recordTrellisError, } from "./metrics.js";
|
|
4
6
|
export { createNatsHeaderCarrier } from "./nats.js";
|
|
5
7
|
export { configureErrorTraceId } from "./result.js";
|
|
6
8
|
export { getTrellisTracer, startClientSpan, startServerSpan, } from "./trellis.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/telemetry/runtime.ts"],"names":[],"mappings":"AAmNA,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAM9D"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { metrics } from "@opentelemetry/api";
|
|
2
|
+
import { getEnv } from "./env.js";
|
|
3
|
+
let initialized = false;
|
|
4
|
+
let provider;
|
|
5
|
+
let metricProvider;
|
|
6
|
+
function runtimeImport(specifier) {
|
|
7
|
+
const load = new Function("specifier", "return import(specifier);");
|
|
8
|
+
return load(specifier);
|
|
9
|
+
}
|
|
10
|
+
async function loadTracingRuntime() {
|
|
11
|
+
const [traceNode, otlp, traceBase, resources, semantic] = await Promise.all([
|
|
12
|
+
runtimeImport(["@opentelemetry", "sdk-trace-node"].join("/")),
|
|
13
|
+
runtimeImport(["@opentelemetry", "exporter-trace-otlp-proto"].join("/")),
|
|
14
|
+
runtimeImport(["@opentelemetry", "sdk-trace-base"].join("/")),
|
|
15
|
+
runtimeImport(["@opentelemetry", "resources"].join("/")),
|
|
16
|
+
runtimeImport(["@opentelemetry", "semantic-conventions"].join("/")),
|
|
17
|
+
]);
|
|
18
|
+
return {
|
|
19
|
+
NodeTracerProvider: traceNode.NodeTracerProvider,
|
|
20
|
+
OTLPTraceExporter: otlp.OTLPTraceExporter,
|
|
21
|
+
BatchSpanProcessor: traceBase.BatchSpanProcessor,
|
|
22
|
+
ConsoleSpanExporter: traceBase.ConsoleSpanExporter,
|
|
23
|
+
resourceFromAttributes: resources.resourceFromAttributes,
|
|
24
|
+
ATTR_SERVICE_NAME: semantic.ATTR_SERVICE_NAME,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
async function loadMetricsRuntime() {
|
|
28
|
+
const [sdkMetrics, otlp, resources, semantic] = await Promise.all([
|
|
29
|
+
runtimeImport(["@opentelemetry", "sdk-metrics"].join("/")),
|
|
30
|
+
runtimeImport(["@opentelemetry", "exporter-metrics-otlp-proto"].join("/")),
|
|
31
|
+
runtimeImport(["@opentelemetry", "resources"].join("/")),
|
|
32
|
+
runtimeImport(["@opentelemetry", "semantic-conventions"].join("/")),
|
|
33
|
+
]);
|
|
34
|
+
return {
|
|
35
|
+
MeterProvider: sdkMetrics.MeterProvider,
|
|
36
|
+
PeriodicExportingMetricReader: sdkMetrics.PeriodicExportingMetricReader,
|
|
37
|
+
ConsoleMetricExporter: sdkMetrics.ConsoleMetricExporter,
|
|
38
|
+
OTLPMetricExporter: otlp.OTLPMetricExporter,
|
|
39
|
+
resourceFromAttributes: resources.resourceFromAttributes,
|
|
40
|
+
ATTR_SERVICE_NAME: semantic.ATTR_SERVICE_NAME,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
async function initTracingRuntime(serviceName) {
|
|
44
|
+
const endpoint = getEnv("OTEL_EXPORTER_OTLP_ENDPOINT");
|
|
45
|
+
const consoleTracing = getEnv("OTEL_TRACES_CONSOLE") === "true";
|
|
46
|
+
if (!endpoint && !consoleTracing) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
const runtime = await loadTracingRuntime();
|
|
51
|
+
const spanProcessors = [];
|
|
52
|
+
if (endpoint) {
|
|
53
|
+
spanProcessors.push(new runtime.BatchSpanProcessor(new runtime.OTLPTraceExporter({ url: `${endpoint}/v1/traces` })));
|
|
54
|
+
}
|
|
55
|
+
if (consoleTracing) {
|
|
56
|
+
spanProcessors.push(new runtime.BatchSpanProcessor(new runtime.ConsoleSpanExporter()));
|
|
57
|
+
}
|
|
58
|
+
const nextProvider = new runtime.NodeTracerProvider({
|
|
59
|
+
resource: runtime.resourceFromAttributes({
|
|
60
|
+
[runtime.ATTR_SERVICE_NAME]: serviceName,
|
|
61
|
+
}),
|
|
62
|
+
...(spanProcessors.length > 0 ? { spanProcessors } : {}),
|
|
63
|
+
});
|
|
64
|
+
provider = nextProvider;
|
|
65
|
+
nextProvider.register();
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
console.warn("Failed to initialize tracing runtime", error);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function metricEndpoint() {
|
|
72
|
+
const metricsEndpoint = getEnv("OTEL_EXPORTER_OTLP_METRICS_ENDPOINT");
|
|
73
|
+
if (metricsEndpoint)
|
|
74
|
+
return metricsEndpoint;
|
|
75
|
+
const endpoint = getEnv("OTEL_EXPORTER_OTLP_ENDPOINT");
|
|
76
|
+
if (!endpoint)
|
|
77
|
+
return undefined;
|
|
78
|
+
return `${endpoint.replace(/\/$/, "")}/v1/metrics`;
|
|
79
|
+
}
|
|
80
|
+
function metricExportIntervalMillis() {
|
|
81
|
+
const configured = getEnv("OTEL_METRIC_EXPORT_INTERVAL");
|
|
82
|
+
if (!configured)
|
|
83
|
+
return undefined;
|
|
84
|
+
const parsed = Number(configured);
|
|
85
|
+
if (!Number.isFinite(parsed) || parsed <= 0)
|
|
86
|
+
return undefined;
|
|
87
|
+
return Math.trunc(parsed);
|
|
88
|
+
}
|
|
89
|
+
async function initMetricsRuntime(serviceName) {
|
|
90
|
+
const endpoint = metricEndpoint();
|
|
91
|
+
const consoleMetrics = getEnv("TRELLIS_METRICS_CONSOLE") === "true";
|
|
92
|
+
if (!endpoint && !consoleMetrics) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
const runtime = await loadMetricsRuntime();
|
|
97
|
+
const readers = [];
|
|
98
|
+
const exportIntervalMillis = metricExportIntervalMillis();
|
|
99
|
+
if (endpoint) {
|
|
100
|
+
readers.push(new runtime.PeriodicExportingMetricReader({
|
|
101
|
+
exporter: new runtime.OTLPMetricExporter({ url: endpoint }),
|
|
102
|
+
...(exportIntervalMillis !== undefined
|
|
103
|
+
? { exportIntervalMillis }
|
|
104
|
+
: {}),
|
|
105
|
+
}));
|
|
106
|
+
}
|
|
107
|
+
if (consoleMetrics) {
|
|
108
|
+
readers.push(new runtime.PeriodicExportingMetricReader({
|
|
109
|
+
exporter: new runtime.ConsoleMetricExporter(),
|
|
110
|
+
...(exportIntervalMillis !== undefined
|
|
111
|
+
? { exportIntervalMillis }
|
|
112
|
+
: {}),
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
115
|
+
const nextMetricProvider = new runtime.MeterProvider({
|
|
116
|
+
resource: runtime.resourceFromAttributes({
|
|
117
|
+
[runtime.ATTR_SERVICE_NAME]: serviceName,
|
|
118
|
+
}),
|
|
119
|
+
...(readers.length > 0 ? { readers } : {}),
|
|
120
|
+
});
|
|
121
|
+
metricProvider = nextMetricProvider;
|
|
122
|
+
metrics.setGlobalMeterProvider(nextMetricProvider);
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
console.warn("Failed to initialize metrics runtime", error);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
export function initTelemetryRuntime(serviceName) {
|
|
129
|
+
if (initialized)
|
|
130
|
+
return;
|
|
131
|
+
initialized = true;
|
|
132
|
+
void initTracingRuntime(serviceName);
|
|
133
|
+
void initMetricsRuntime(serviceName);
|
|
134
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry.d.ts","sourceRoot":"","sources":["../src/telemetry.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAC7B,cAAc,oBAAoB,CAAC"}
|
package/esm/telemetry.js
ADDED
package/esm/transfer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transfer.d.ts","sourceRoot":"","sources":["../src/transfer.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EAGX,KAAK,MAAM,IAAI,UAAU,EAC1B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAIL,KAAK,OAAO,EACZ,KAAK,cAAc,EAEpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,IAAI,EAAE,EAAE,KAAK,MAAM,EAAE,MAAM,SAAS,CAAC;AAI5C,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"transfer.d.ts","sourceRoot":"","sources":["../src/transfer.ts"],"names":[],"mappings":"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"}
|
package/esm/transfer.js
CHANGED
|
@@ -17,7 +17,7 @@ import { ulid } from "ulid";
|
|
|
17
17
|
import { buildProofInput, verifyProof } from "./auth/proof.js";
|
|
18
18
|
import { base64urlEncode, sha256 } from "./auth/utils.js";
|
|
19
19
|
import { TransferError } from "./errors/TransferError.js";
|
|
20
|
-
import { createNatsHeaderCarrier, injectTraceContext } from "./
|
|
20
|
+
import { createNatsHeaderCarrier, injectTraceContext, recordTrellisError, } from "./telemetry/mod.js";
|
|
21
21
|
const TRANSFER_SEQUENCE_HEADER = "trellis-transfer-seq";
|
|
22
22
|
const TRANSFER_EOF_HEADER = "trellis-transfer-eof";
|
|
23
23
|
export const FileInfoSchema = Type.Object({
|
|
@@ -130,7 +130,7 @@ function deserializeTransferError(msg, operation) {
|
|
|
130
130
|
try {
|
|
131
131
|
const value = JSON.parse(msg.string());
|
|
132
132
|
return new TransferError({
|
|
133
|
-
operation
|
|
133
|
+
operation,
|
|
134
134
|
context: value.context,
|
|
135
135
|
cause: value.message ? new Error(value.message) : undefined,
|
|
136
136
|
});
|
|
@@ -139,6 +139,16 @@ function deserializeTransferError(msg, operation) {
|
|
|
139
139
|
return new TransferError({ operation, cause });
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
|
+
function recordTransferError(error, direction, phase) {
|
|
143
|
+
recordTrellisError(error, {
|
|
144
|
+
surface: "transfer",
|
|
145
|
+
direction,
|
|
146
|
+
operation: error.operation ?? direction,
|
|
147
|
+
phase,
|
|
148
|
+
messagingSystem: "nats",
|
|
149
|
+
});
|
|
150
|
+
return error;
|
|
151
|
+
}
|
|
142
152
|
function receiveStream(sub, timeoutMs) {
|
|
143
153
|
const iterator = sub[Symbol.asyncIterator]();
|
|
144
154
|
return new ReadableStream({
|
|
@@ -179,9 +189,10 @@ function receiveStream(sub, timeoutMs) {
|
|
|
179
189
|
}
|
|
180
190
|
catch (cause) {
|
|
181
191
|
sub.unsubscribe();
|
|
182
|
-
|
|
192
|
+
const error = cause instanceof TransferError
|
|
183
193
|
? cause
|
|
184
|
-
: new TransferError({ operation: "stream", cause })
|
|
194
|
+
: new TransferError({ operation: "stream", cause });
|
|
195
|
+
controller.error(recordTransferError(error, "receive", "stream"));
|
|
185
196
|
}
|
|
186
197
|
},
|
|
187
198
|
cancel() {
|
|
@@ -283,7 +294,7 @@ export class SendTransferHandle extends BaseTransferHandle {
|
|
|
283
294
|
return AsyncResult.from((async () => {
|
|
284
295
|
const valid = this.validateGrant(__classPrivateFieldGet(this, _SendTransferHandle_grant, "f"), "send").take();
|
|
285
296
|
if (isErr(valid)) {
|
|
286
|
-
return Result.err(valid.error);
|
|
297
|
+
return Result.err(recordTransferError(valid.error, "send", "grant"));
|
|
287
298
|
}
|
|
288
299
|
let sentBytes = 0;
|
|
289
300
|
let seq = 0;
|
|
@@ -292,14 +303,14 @@ export class SendTransferHandle extends BaseTransferHandle {
|
|
|
292
303
|
sentBytes += chunk.length;
|
|
293
304
|
if (__classPrivateFieldGet(this, _SendTransferHandle_grant, "f").maxBytes !== undefined &&
|
|
294
305
|
sentBytes > __classPrivateFieldGet(this, _SendTransferHandle_grant, "f").maxBytes) {
|
|
295
|
-
return Result.err(new TransferError({
|
|
306
|
+
return Result.err(recordTransferError(new TransferError({
|
|
296
307
|
operation: "send",
|
|
297
308
|
context: {
|
|
298
309
|
reason: "max_bytes_exceeded",
|
|
299
310
|
maxBytes: __classPrivateFieldGet(this, _SendTransferHandle_grant, "f").maxBytes,
|
|
300
311
|
attemptedBytes: sentBytes,
|
|
301
312
|
},
|
|
302
|
-
}));
|
|
313
|
+
}), "send", "validation"));
|
|
303
314
|
}
|
|
304
315
|
const headers = await this.buildHeaders(__classPrivateFieldGet(this, _SendTransferHandle_grant, "f").subject, chunk, seq, false);
|
|
305
316
|
const response = await AsyncResult.try(() => this.nc.request(__classPrivateFieldGet(this, _SendTransferHandle_grant, "f").subject, chunk, {
|
|
@@ -307,11 +318,11 @@ export class SendTransferHandle extends BaseTransferHandle {
|
|
|
307
318
|
headers,
|
|
308
319
|
})).take();
|
|
309
320
|
if (isErr(response)) {
|
|
310
|
-
return Result.err(new TransferError({ operation: "send", cause: response.error }));
|
|
321
|
+
return Result.err(recordTransferError(new TransferError({ operation: "send", cause: response.error }), "send", "send"));
|
|
311
322
|
}
|
|
312
323
|
const ack = parseTransferAck(response, "send").take();
|
|
313
324
|
if (isErr(ack)) {
|
|
314
|
-
return Result.err(ack.error);
|
|
325
|
+
return Result.err(recordTransferError(ack.error, "send", "ack"));
|
|
315
326
|
}
|
|
316
327
|
if (ack.status === "complete") {
|
|
317
328
|
completed = ack.info;
|
|
@@ -324,20 +335,20 @@ export class SendTransferHandle extends BaseTransferHandle {
|
|
|
324
335
|
headers: finalHeaders,
|
|
325
336
|
})).take();
|
|
326
337
|
if (isErr(finalResponse)) {
|
|
327
|
-
return Result.err(new TransferError({
|
|
338
|
+
return Result.err(recordTransferError(new TransferError({
|
|
328
339
|
operation: "send",
|
|
329
340
|
cause: finalResponse.error,
|
|
330
|
-
}));
|
|
341
|
+
}), "send", "send"));
|
|
331
342
|
}
|
|
332
343
|
const finalAck = parseTransferAck(finalResponse, "send").take();
|
|
333
344
|
if (isErr(finalAck)) {
|
|
334
|
-
return Result.err(finalAck.error);
|
|
345
|
+
return Result.err(recordTransferError(finalAck.error, "send", "ack"));
|
|
335
346
|
}
|
|
336
347
|
if (finalAck.status !== "complete") {
|
|
337
|
-
return Result.err(new TransferError({
|
|
348
|
+
return Result.err(recordTransferError(new TransferError({
|
|
338
349
|
operation: "send",
|
|
339
350
|
context: { reason: "missing_completion" },
|
|
340
|
-
}));
|
|
351
|
+
}), "send", "ack"));
|
|
341
352
|
}
|
|
342
353
|
return Result.ok(finalAck.info ?? completed);
|
|
343
354
|
})());
|
|
@@ -354,7 +365,7 @@ export class ReceiveTransferHandle extends BaseTransferHandle {
|
|
|
354
365
|
return AsyncResult.from((async () => {
|
|
355
366
|
const valid = this.validateGrant(__classPrivateFieldGet(this, _ReceiveTransferHandle_grant, "f"), "stream").take();
|
|
356
367
|
if (isErr(valid)) {
|
|
357
|
-
return Result.err(valid.error);
|
|
368
|
+
return Result.err(recordTransferError(valid.error, "receive", "grant"));
|
|
358
369
|
}
|
|
359
370
|
const inbox = createInbox(`_INBOX.${this.auth.sessionKey.slice(0, 16)}`);
|
|
360
371
|
const sub = this.nc.subscribe(inbox);
|
|
@@ -369,7 +380,7 @@ export class ReceiveTransferHandle extends BaseTransferHandle {
|
|
|
369
380
|
}
|
|
370
381
|
catch (cause) {
|
|
371
382
|
sub.unsubscribe();
|
|
372
|
-
return Result.err(new TransferError({ operation: "stream", cause }));
|
|
383
|
+
return Result.err(recordTransferError(new TransferError({ operation: "stream", cause }), "receive", "send"));
|
|
373
384
|
}
|
|
374
385
|
return Result.ok(receiveStream(sub, this.timeoutMs));
|
|
375
386
|
})());
|