@apifuse/provider-sdk 2.2.0-beta.2 → 2.2.0-beta.21
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/AUTHORING.md +487 -0
- package/CHANGELOG.md +90 -0
- package/README.md +49 -3
- package/SUBMISSION.md +1 -1
- package/bin/apifuse-check.ts +44 -59
- package/bin/apifuse-create.ts +1 -1
- package/bin/apifuse-dev.ts +27 -52
- package/bin/apifuse-pack-check.ts +14 -0
- package/bin/apifuse-pack-smoke.ts +36 -81
- package/bin/apifuse-pack-types.ts +305 -0
- package/bin/apifuse-perf.ts +45 -127
- package/bin/apifuse-record.ts +659 -111
- package/bin/apifuse-submit-check.ts +546 -48
- package/bin/apifuse-sync-assets.ts +117 -0
- package/bin/apifuse.ts +1 -1
- package/bin/submit-check-delimited-text.ts +50 -0
- package/bin/submit-check-xml-semantics.ts +204 -0
- package/bin/submit-check-xml.ts +134 -0
- package/dist/auth-turn/index.d.ts +3 -3
- package/dist/auth.d.ts +2 -2
- package/dist/auth.js +9 -18
- package/dist/ceremonies/index.d.ts +9 -1
- package/dist/ceremonies/index.js +65 -18
- package/dist/cli/commands.d.ts +1 -1
- package/dist/cli/commands.js +8 -0
- package/dist/cli/create.d.ts +3 -0
- package/dist/cli/create.js +34 -35
- package/dist/cli/prompt-assets.d.ts +80 -0
- package/dist/cli/prompt-assets.js +743 -0
- package/dist/cli/templates/provider/AGENTS.md.tpl +17 -8
- package/dist/config/loader.d.ts +176 -8
- package/dist/config/loader.js +424 -95
- package/dist/contract-serialization.d.ts +2 -2
- package/dist/contract-serialization.js +3 -6
- package/dist/contract-types.d.ts +2 -2
- package/dist/contract.d.ts +3 -3
- package/dist/contract.js +4 -6
- package/dist/define.d.ts +9 -1
- package/dist/define.js +304 -119
- package/dist/dev.d.ts +1 -1
- package/dist/dev.js +1 -1
- package/dist/error-resolution.d.ts +2 -0
- package/dist/error-resolution.js +90 -0
- package/dist/errors.d.ts +22 -1
- package/dist/errors.js +88 -0
- package/dist/fixture-sanitization.d.ts +26 -0
- package/dist/fixture-sanitization.js +216 -0
- package/dist/i18n/catalog.d.ts +2 -2
- package/dist/i18n/catalog.js +4 -10
- package/dist/i18n/index.d.ts +2 -2
- package/dist/i18n/index.js +2 -2
- package/dist/i18n/keys.d.ts +2 -2
- package/dist/index.d.ts +46 -42
- package/dist/index.js +41 -37
- package/dist/lint.d.ts +1 -1
- package/dist/lint.js +8 -15
- package/dist/native-address.d.ts +43 -0
- package/dist/native-address.js +281 -0
- package/dist/native-egress-policy.d.ts +31 -0
- package/dist/native-egress-policy.js +288 -0
- package/dist/observability.d.ts +5 -2
- package/dist/observability.js +48 -1
- package/dist/provider.d.ts +12 -11
- package/dist/provider.js +10 -9
- package/dist/public-schema-field-lint.d.ts +1 -1
- package/dist/recipes/gov-api.js +1 -1
- package/dist/runtime/auth-flow.d.ts +2 -1
- package/dist/runtime/auth-flow.js +4 -3
- package/dist/runtime/browser.d.ts +1 -1
- package/dist/runtime/browser.js +15 -29
- package/dist/runtime/cache.d.ts +1 -1
- package/dist/runtime/cache.js +4 -8
- package/dist/runtime/choice.d.ts +1 -1
- package/dist/runtime/choice.js +31 -35
- package/dist/runtime/credential.d.ts +1 -1
- package/dist/runtime/credential.js +1 -1
- package/dist/runtime/env.d.ts +1 -1
- package/dist/runtime/executor.d.ts +1 -1
- package/dist/runtime/executor.js +31 -4
- package/dist/runtime/http.d.ts +2 -2
- package/dist/runtime/http.js +387 -47
- package/dist/runtime/insights.d.ts +1 -1
- package/dist/runtime/insights.js +6 -13
- package/dist/runtime/instrumentation.d.ts +2 -2
- package/dist/runtime/instrumentation.js +345 -22
- package/dist/runtime/keyring.js +1 -1
- package/dist/runtime/namespace.js +1 -1
- package/dist/runtime/native-network.d.ts +127 -0
- package/dist/runtime/native-network.js +1298 -0
- package/dist/runtime/otlp.d.ts +1 -1
- package/dist/runtime/perf.d.ts +1 -1
- package/dist/runtime/provider.d.ts +1 -1
- package/dist/runtime/provider.js +1 -2
- package/dist/runtime/proxy-errors.d.ts +1 -1
- package/dist/runtime/proxy-errors.js +9 -7
- package/dist/runtime/proxy-nodemaven.d.ts +56 -0
- package/dist/runtime/proxy-nodemaven.js +146 -0
- package/dist/runtime/proxy-retry-policy.d.ts +2 -2
- package/dist/runtime/proxy-retry-policy.js +2 -2
- package/dist/runtime/proxy-telemetry.d.ts +2 -1
- package/dist/runtime/proxy-telemetry.js +55 -52
- package/dist/runtime/redirects.d.ts +29 -0
- package/dist/runtime/redirects.js +36 -0
- package/dist/runtime/redis.d.ts +1 -1
- package/dist/runtime/redis.js +2 -4
- package/dist/runtime/request-options.d.ts +68 -1
- package/dist/runtime/request-options.js +548 -0
- package/dist/runtime/secrets.d.ts +27 -0
- package/dist/runtime/secrets.js +51 -0
- package/dist/runtime/state.d.ts +2 -2
- package/dist/runtime/state.js +238 -26
- package/dist/runtime/stealth.d.ts +5 -3
- package/dist/runtime/stealth.js +423 -143
- package/dist/runtime/stt.d.ts +1 -1
- package/dist/runtime/stt.js +11 -15
- package/dist/runtime/trace.d.ts +2 -2
- package/dist/runtime/trace.js +2 -4
- package/dist/runtime/waterfall.d.ts +1 -1
- package/dist/schema.d.ts +1 -1
- package/dist/schema.js +7 -15
- package/dist/serve.d.ts +1 -1
- package/dist/serve.js +1 -1
- package/dist/server/index.d.ts +7 -7
- package/dist/server/index.js +6 -6
- package/dist/server/self-test-input-tokens.d.ts +2 -1
- package/dist/server/self-test-input-tokens.js +18 -14
- package/dist/server/self-test-redaction.d.ts +1 -1
- package/dist/server/self-test-redaction.js +1 -1
- package/dist/server/self-test.d.ts +104 -3
- package/dist/server/self-test.js +673 -115
- package/dist/server/serve.d.ts +116 -4
- package/dist/server/serve.js +799 -128
- package/dist/server/types.d.ts +34 -9
- package/dist/server/types.js +8 -1
- package/dist/stateful/errors.d.ts +14 -0
- package/dist/stateful/errors.js +14 -0
- package/dist/stateful/http-provider-event-emitter.d.ts +40 -0
- package/dist/stateful/http-provider-event-emitter.js +237 -0
- package/dist/stateful/http-session-owner-registry.d.ts +44 -0
- package/dist/stateful/http-session-owner-registry.js +210 -0
- package/dist/stateful/index.d.ts +18 -0
- package/dist/stateful/index.js +18 -0
- package/dist/stateful/provider-event-delivery-failures.d.ts +32 -0
- package/dist/stateful/provider-event-delivery-failures.js +43 -0
- package/dist/stateful/provider-event-pipeline-metrics.d.ts +46 -0
- package/dist/stateful/provider-event-pipeline-metrics.js +48 -0
- package/dist/stateful/provider-event-pipeline.d.ts +50 -0
- package/dist/stateful/provider-event-pipeline.js +1 -0
- package/dist/stateful/provider-events.d.ts +101 -0
- package/dist/stateful/provider-events.js +289 -0
- package/dist/stateful/session-key.d.ts +15 -0
- package/dist/stateful/session-key.js +86 -0
- package/dist/stateful/stateful-provider-adapter-context.d.ts +5 -0
- package/dist/stateful/stateful-provider-adapter-context.js +42 -0
- package/dist/stateful/stateful-provider-adapter-metrics.d.ts +15 -0
- package/dist/stateful/stateful-provider-adapter-metrics.js +21 -0
- package/dist/stateful/stateful-provider-adapter.d.ts +98 -0
- package/dist/stateful/stateful-provider-adapter.js +287 -0
- package/dist/stateful/stateful-provider-observability.d.ts +62 -0
- package/dist/stateful/stateful-provider-observability.js +161 -0
- package/dist/stateful/stateful-provider-owner-forwarder.d.ts +41 -0
- package/dist/stateful/stateful-provider-owner-forwarder.js +215 -0
- package/dist/stateful/stateful-provider-runtime-context.d.ts +32 -0
- package/dist/stateful/stateful-provider-runtime-context.js +60 -0
- package/dist/stateful/stateful-provider-runtime-executor.d.ts +34 -0
- package/dist/stateful/stateful-provider-runtime-executor.js +52 -0
- package/dist/stateful/stateful-provider-session-routing.d.ts +71 -0
- package/dist/stateful/stateful-provider-session-routing.js +353 -0
- package/dist/stateful/stateful-provider-session-runtime.d.ts +98 -0
- package/dist/stateful/stateful-provider-session-runtime.js +245 -0
- package/dist/stateful-signing.d.ts +18 -0
- package/dist/stateful-signing.js +27 -0
- package/dist/stealth/profiles.d.ts +1 -1
- package/dist/stealth/profiles.js +5 -14
- package/dist/stream-evidence.d.ts +74 -0
- package/dist/stream-evidence.js +785 -0
- package/dist/stream.d.ts +1 -1
- package/dist/testing/index.d.ts +2 -2
- package/dist/testing/index.js +2 -2
- package/dist/testing/run.d.ts +32 -2
- package/dist/testing/run.js +478 -28
- package/dist/types.d.ts +342 -14
- package/dist/types.js +1 -0
- package/dist/user-input.d.ts +30 -0
- package/dist/user-input.js +66 -0
- package/package.json +16 -5
- package/src/auth-turn/index.ts +1 -1
- package/src/auth.ts +28 -86
- package/src/ceremonies/index.ts +103 -78
- package/src/cli/commands.ts +10 -0
- package/src/cli/create.ts +42 -35
- package/src/cli/prompt-assets.ts +865 -0
- package/src/cli/templates/provider/AGENTS.md.tpl +17 -8
- package/src/config/loader.ts +652 -204
- package/src/contract-serialization.ts +5 -11
- package/src/contract-types.ts +2 -2
- package/src/contract.ts +12 -28
- package/src/define.ts +499 -498
- package/src/dev.ts +4 -9
- package/src/error-resolution.ts +91 -0
- package/src/errors.ts +110 -5
- package/src/fixture-sanitization.ts +247 -0
- package/src/i18n/catalog.ts +10 -32
- package/src/i18n/index.ts +2 -2
- package/src/i18n/keys.ts +5 -11
- package/src/index.ts +112 -42
- package/src/lint.ts +88 -152
- package/src/native-address.ts +340 -0
- package/src/native-egress-policy.ts +358 -0
- package/src/observability.ts +51 -1
- package/src/provider.ts +66 -11
- package/src/public-schema-field-lint.ts +7 -33
- package/src/recipes/gov-api.ts +2 -5
- package/src/runtime/auth-flow.ts +7 -7
- package/src/runtime/browser.ts +64 -187
- package/src/runtime/cache.ts +20 -67
- package/src/runtime/choice.ts +79 -132
- package/src/runtime/credential.ts +2 -2
- package/src/runtime/env.ts +1 -1
- package/src/runtime/executor.ts +43 -20
- package/src/runtime/http.ts +494 -57
- package/src/runtime/insights.ts +15 -53
- package/src/runtime/instrumentation.ts +495 -66
- package/src/runtime/keyring.ts +7 -19
- package/src/runtime/namespace.ts +2 -7
- package/src/runtime/native-network.ts +1686 -0
- package/src/runtime/otlp.ts +12 -23
- package/src/runtime/perf.ts +1 -1
- package/src/runtime/provider.ts +4 -9
- package/src/runtime/proxy-errors.ts +29 -42
- package/src/runtime/proxy-nodemaven.ts +221 -0
- package/src/runtime/proxy-retry-policy.ts +3 -3
- package/src/runtime/proxy-telemetry.ts +79 -77
- package/src/runtime/redirects.ts +66 -0
- package/src/runtime/redis.ts +4 -12
- package/src/runtime/request-options.ts +679 -9
- package/src/runtime/secrets.ts +64 -0
- package/src/runtime/state.ts +353 -133
- package/src/runtime/stealth.ts +505 -154
- package/src/runtime/stt.ts +38 -94
- package/src/runtime/trace.ts +14 -44
- package/src/runtime/waterfall.ts +5 -18
- package/src/schema.ts +23 -84
- package/src/serve.ts +1 -1
- package/src/server/index.ts +29 -7
- package/src/server/self-test-input-tokens.ts +29 -14
- package/src/server/self-test-redaction.ts +2 -2
- package/src/server/self-test.ts +857 -132
- package/src/server/serve.ts +1151 -328
- package/src/server/types.ts +12 -13
- package/src/stateful/README.md +146 -0
- package/src/stateful/errors.ts +23 -0
- package/src/stateful/http-provider-event-emitter.ts +314 -0
- package/src/stateful/http-session-owner-registry.ts +306 -0
- package/src/stateful/index.ts +18 -0
- package/src/stateful/provider-event-delivery-failures.ts +80 -0
- package/src/stateful/provider-event-pipeline-metrics.ts +95 -0
- package/src/stateful/provider-event-pipeline.ts +61 -0
- package/src/stateful/provider-events.ts +462 -0
- package/src/stateful/session-key.ts +111 -0
- package/src/stateful/stateful-provider-adapter-context.ts +59 -0
- package/src/stateful/stateful-provider-adapter-metrics.ts +48 -0
- package/src/stateful/stateful-provider-adapter.ts +562 -0
- package/src/stateful/stateful-provider-observability.ts +261 -0
- package/src/stateful/stateful-provider-owner-forwarder.ts +287 -0
- package/src/stateful/stateful-provider-runtime-context.ts +92 -0
- package/src/stateful/stateful-provider-runtime-executor.ts +96 -0
- package/src/stateful/stateful-provider-session-routing.ts +555 -0
- package/src/stateful/stateful-provider-session-runtime.ts +403 -0
- package/src/stateful-signing.ts +46 -0
- package/src/stealth/profiles.ts +10 -26
- package/src/stream-evidence.ts +988 -0
- package/src/stream.ts +8 -19
- package/src/testing/index.ts +10 -2
- package/src/testing/run.ts +653 -74
- package/src/types.ts +408 -28
- package/src/user-input.ts +118 -0
- package/dist/cli/templates/provider/CLAUDE.md.tpl +0 -1
- package/src/cli/templates/provider/CLAUDE.md.tpl +0 -1
- /package/dist/cli/templates/provider/{skills → .agents/skills}/fixtures-and-recording/SKILL.md.tpl +0 -0
- /package/dist/cli/templates/provider/{skills → .agents/skills}/health-checks-and-fail-closed/SKILL.md.tpl +0 -0
- /package/dist/cli/templates/provider/{skills → .agents/skills}/normalization-standards/SKILL.md.tpl +0 -0
- /package/dist/cli/templates/provider/{skills → .agents/skills}/pagination-and-counts/SKILL.md.tpl +0 -0
- /package/dist/cli/templates/provider/{skills → .agents/skills}/upstream-contract-verification/SKILL.md.tpl +0 -0
- /package/dist/cli/templates/provider/{skills → .agents/skills}/upstream-notes/README.md.tpl +0 -0
- /package/src/cli/templates/provider/{skills → .agents/skills}/fixtures-and-recording/SKILL.md.tpl +0 -0
- /package/src/cli/templates/provider/{skills → .agents/skills}/health-checks-and-fail-closed/SKILL.md.tpl +0 -0
- /package/src/cli/templates/provider/{skills → .agents/skills}/normalization-standards/SKILL.md.tpl +0 -0
- /package/src/cli/templates/provider/{skills → .agents/skills}/pagination-and-counts/SKILL.md.tpl +0 -0
- /package/src/cli/templates/provider/{skills → .agents/skills}/upstream-contract-verification/SKILL.md.tpl +0 -0
- /package/src/cli/templates/provider/{skills → .agents/skills}/upstream-notes/README.md.tpl +0 -0
|
@@ -1,34 +1,56 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
HttpStreamResponse,
|
|
3
|
+
ProviderContext,
|
|
4
|
+
RequestOptions,
|
|
5
|
+
SseMessage,
|
|
6
|
+
StealthSession,
|
|
7
|
+
StealthRedirectRunResult,
|
|
8
|
+
} from "../types.js";
|
|
9
|
+
import { readableBytes, readableLines, readableTextChunks } from "../stream.js";
|
|
10
|
+
import {
|
|
11
|
+
parseHttpRequestInvocation,
|
|
12
|
+
isSensitiveKey,
|
|
13
|
+
redactSensitiveError,
|
|
14
|
+
redactSensitiveText,
|
|
15
|
+
redactUrlQueryParams,
|
|
16
|
+
requestOptionsFromHttpInvocation,
|
|
17
|
+
serializeRequestUrl,
|
|
18
|
+
type SerializedRequestUrl,
|
|
19
|
+
} from "./request-options.js";
|
|
2
20
|
import {
|
|
3
21
|
type CreateTraceContextOptions,
|
|
4
22
|
createTraceContext,
|
|
5
23
|
getTraceRecorder,
|
|
6
24
|
type TraceContext,
|
|
7
|
-
} from "./trace";
|
|
25
|
+
} from "./trace.js";
|
|
8
26
|
|
|
9
27
|
export interface InstrumentationOptions extends CreateTraceContextOptions {}
|
|
10
28
|
|
|
11
|
-
export type InstrumentedProviderContext<T extends ProviderContext> = Omit<
|
|
12
|
-
T,
|
|
13
|
-
"trace"
|
|
14
|
-
> & {
|
|
29
|
+
export type InstrumentedProviderContext<T extends ProviderContext> = Omit<T, "trace"> & {
|
|
15
30
|
trace: TraceContext;
|
|
16
31
|
};
|
|
17
32
|
|
|
18
|
-
type InstrumentedNamespace =
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
33
|
+
type InstrumentedNamespace = "http" | "stealth" | "browser" | "session" | "state";
|
|
34
|
+
|
|
35
|
+
const BROWSER_PAGE_METHODS = new Set(["goto", "fill", "click", "type", "waitForSelector"]);
|
|
36
|
+
const DIAGNOSTIC_BASE_URL = "http://apifuse-instrumentation.invalid";
|
|
37
|
+
|
|
38
|
+
type RequestDiagnostics = {
|
|
39
|
+
diagnosticUrlDegraded?: boolean;
|
|
40
|
+
requestId?: string;
|
|
41
|
+
serializedUrl?: SerializedRequestUrl;
|
|
42
|
+
sensitiveParamNames: readonly string[];
|
|
43
|
+
sensitiveValues: readonly string[];
|
|
44
|
+
traceUrl?: string;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
function isThenable(value: unknown): value is PromiseLike<unknown> {
|
|
48
|
+
return (
|
|
49
|
+
(typeof value === "object" || typeof value === "function") &&
|
|
50
|
+
value !== null &&
|
|
51
|
+
typeof (value as { then?: unknown }).then === "function"
|
|
52
|
+
);
|
|
53
|
+
}
|
|
32
54
|
|
|
33
55
|
function getErrorStatus(error: unknown): number | undefined {
|
|
34
56
|
if (
|
|
@@ -59,10 +81,7 @@ function getResponseDuration(result: unknown): number | undefined {
|
|
|
59
81
|
return undefined;
|
|
60
82
|
}
|
|
61
83
|
|
|
62
|
-
function getResponseStatus(
|
|
63
|
-
namespace: InstrumentedNamespace,
|
|
64
|
-
result: unknown,
|
|
65
|
-
): number | undefined {
|
|
84
|
+
function getResponseStatus(namespace: InstrumentedNamespace, result: unknown): number | undefined {
|
|
66
85
|
if (
|
|
67
86
|
typeof result === "object" &&
|
|
68
87
|
result !== null &&
|
|
@@ -101,18 +120,236 @@ function getUrl(
|
|
|
101
120
|
return undefined;
|
|
102
121
|
}
|
|
103
122
|
|
|
123
|
+
function requestOptionsForInvocation(
|
|
124
|
+
namespace: InstrumentedNamespace,
|
|
125
|
+
methodName: string,
|
|
126
|
+
args: readonly unknown[],
|
|
127
|
+
): RequestOptions | undefined {
|
|
128
|
+
if (namespace === "http") {
|
|
129
|
+
const invocation = parseHttpRequestInvocation(methodName, [...args]);
|
|
130
|
+
return invocation ? requestOptionsFromHttpInvocation(invocation) : undefined;
|
|
131
|
+
}
|
|
132
|
+
if (namespace !== "stealth" || methodName !== "fetch" || typeof args[0] !== "string") {
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
const options = args[1];
|
|
136
|
+
return options !== null && typeof options === "object" && !Array.isArray(options)
|
|
137
|
+
? (options as RequestOptions)
|
|
138
|
+
: undefined;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function fallbackSensitiveValues(options?: RequestOptions): readonly string[] {
|
|
142
|
+
const sensitiveParams = options?.sensitiveParams;
|
|
143
|
+
if (!sensitiveParams || typeof sensitiveParams !== "object") return [];
|
|
144
|
+
return Object.values(sensitiveParams).map(String);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function stripDiagnosticBase(url: string): string {
|
|
148
|
+
return url.startsWith(DIAGNOSTIC_BASE_URL) ? url.slice(DIAGNOSTIC_BASE_URL.length) || "/" : url;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function serializeDiagnosticUrl(
|
|
152
|
+
url: string,
|
|
153
|
+
options?: RequestOptions,
|
|
154
|
+
): { degraded: boolean; serializedUrl: SerializedRequestUrl } {
|
|
155
|
+
try {
|
|
156
|
+
return {
|
|
157
|
+
degraded: false,
|
|
158
|
+
serializedUrl: serializeRequestUrl(url, options?.params, options?.sensitiveParams),
|
|
159
|
+
};
|
|
160
|
+
} catch {
|
|
161
|
+
try {
|
|
162
|
+
const absoluteUrl = new URL(url, DIAGNOSTIC_BASE_URL).toString();
|
|
163
|
+
const serialized = serializeRequestUrl(
|
|
164
|
+
absoluteUrl,
|
|
165
|
+
options?.params,
|
|
166
|
+
options?.sensitiveParams,
|
|
167
|
+
);
|
|
168
|
+
return {
|
|
169
|
+
degraded: false,
|
|
170
|
+
serializedUrl: {
|
|
171
|
+
requestUrl: stripDiagnosticBase(serialized.requestUrl),
|
|
172
|
+
redactedUrl: stripDiagnosticBase(serialized.redactedUrl),
|
|
173
|
+
sensitiveValues: serialized.sensitiveValues,
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
} catch {
|
|
177
|
+
const sensitiveParamNames = Object.keys(options?.sensitiveParams ?? {});
|
|
178
|
+
const structural = redactUrlQueryParams(url, sensitiveParamNames);
|
|
179
|
+
return {
|
|
180
|
+
degraded: true,
|
|
181
|
+
serializedUrl: {
|
|
182
|
+
requestUrl: url,
|
|
183
|
+
redactedUrl: structural.redactedUrl,
|
|
184
|
+
sensitiveValues: [
|
|
185
|
+
...new Set([...fallbackSensitiveValues(options), ...structural.sensitiveValues]),
|
|
186
|
+
],
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function snapshotRequestDiagnostics(
|
|
194
|
+
namespace: InstrumentedNamespace,
|
|
195
|
+
methodName: string,
|
|
196
|
+
args: readonly unknown[],
|
|
197
|
+
): RequestDiagnostics {
|
|
198
|
+
const options = requestOptionsForInvocation(namespace, methodName, args);
|
|
199
|
+
const url = typeof args[0] === "string" ? args[0] : undefined;
|
|
200
|
+
const hasSensitiveParams = Boolean(
|
|
201
|
+
options?.sensitiveParams && Object.keys(options.sensitiveParams).length > 0,
|
|
202
|
+
);
|
|
203
|
+
const sensitiveParamNames = Object.keys(options?.sensitiveParams ?? {});
|
|
204
|
+
const diagnosticUrl =
|
|
205
|
+
hasSensitiveParams && url ? serializeDiagnosticUrl(url, options) : undefined;
|
|
206
|
+
const traceUrl =
|
|
207
|
+
hasSensitiveParams && url
|
|
208
|
+
? serializeDiagnosticUrl(url, { sensitiveParams: options?.sensitiveParams }).serializedUrl
|
|
209
|
+
.redactedUrl
|
|
210
|
+
: undefined;
|
|
211
|
+
return {
|
|
212
|
+
...(diagnosticUrl?.degraded ? { diagnosticUrlDegraded: true } : {}),
|
|
213
|
+
...(hasSensitiveParams ? { requestId: crypto.randomUUID() } : {}),
|
|
214
|
+
serializedUrl: diagnosticUrl?.serializedUrl,
|
|
215
|
+
sensitiveParamNames,
|
|
216
|
+
sensitiveValues:
|
|
217
|
+
diagnosticUrl?.serializedUrl.sensitiveValues ?? fallbackSensitiveValues(options),
|
|
218
|
+
traceUrl,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function sanitizeRequestError(error: unknown, diagnostics: RequestDiagnostics): unknown {
|
|
223
|
+
return redactSensitiveError(
|
|
224
|
+
error,
|
|
225
|
+
diagnostics.sensitiveValues,
|
|
226
|
+
diagnostics.serializedUrl?.requestUrl,
|
|
227
|
+
diagnostics.serializedUrl?.redactedUrl,
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function isHttpStreamResponse(value: unknown): value is HttpStreamResponse {
|
|
232
|
+
return (
|
|
233
|
+
typeof value === "object" &&
|
|
234
|
+
value !== null &&
|
|
235
|
+
"body" in value &&
|
|
236
|
+
value.body instanceof ReadableStream
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function instrumentHttpStreamConsumption(
|
|
241
|
+
value: HttpStreamResponse,
|
|
242
|
+
recorder: NonNullable<ReturnType<typeof getTraceRecorder>>,
|
|
243
|
+
args: unknown[],
|
|
244
|
+
diagnostics: RequestDiagnostics,
|
|
245
|
+
): HttpStreamResponse {
|
|
246
|
+
const source = value.body;
|
|
247
|
+
let reader: ReadableStreamDefaultReader<Uint8Array> | undefined;
|
|
248
|
+
const body = new ReadableStream<Uint8Array>(
|
|
249
|
+
{
|
|
250
|
+
async pull(controller) {
|
|
251
|
+
try {
|
|
252
|
+
reader ??= source.getReader();
|
|
253
|
+
const chunk = await reader.read();
|
|
254
|
+
if (chunk.done) {
|
|
255
|
+
controller.close();
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
controller.enqueue(chunk.value);
|
|
259
|
+
} catch (error) {
|
|
260
|
+
const sanitizedError = sanitizeRequestError(error, diagnostics);
|
|
261
|
+
try {
|
|
262
|
+
await recorder.runSpan(
|
|
263
|
+
"http.stream.consume",
|
|
264
|
+
() => {
|
|
265
|
+
throw sanitizedError;
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
onError: (spanError) =>
|
|
269
|
+
buildSpanAttributes("http", "stream", args, undefined, spanError, diagnostics),
|
|
270
|
+
},
|
|
271
|
+
);
|
|
272
|
+
} catch (recordedError) {
|
|
273
|
+
controller.error(recordedError);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
},
|
|
277
|
+
async cancel(reason) {
|
|
278
|
+
try {
|
|
279
|
+
await (reader ? reader.cancel(reason) : source.cancel(reason));
|
|
280
|
+
} catch (error) {
|
|
281
|
+
throw sanitizeRequestError(error, diagnostics);
|
|
282
|
+
}
|
|
283
|
+
},
|
|
284
|
+
},
|
|
285
|
+
{ highWaterMark: 0 },
|
|
286
|
+
);
|
|
287
|
+
|
|
288
|
+
const instrumented = {
|
|
289
|
+
...value,
|
|
290
|
+
body,
|
|
291
|
+
bytes: () => readableBytes(body),
|
|
292
|
+
textChunks: () => readableTextChunks(body),
|
|
293
|
+
lines: () => readableLines(body),
|
|
294
|
+
} satisfies HttpStreamResponse;
|
|
295
|
+
try {
|
|
296
|
+
Object.assign(value, instrumented);
|
|
297
|
+
return value;
|
|
298
|
+
} catch {
|
|
299
|
+
return instrumented;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function isAsyncIterable<T = unknown>(value: unknown): value is AsyncIterable<T> {
|
|
304
|
+
return (
|
|
305
|
+
typeof value === "object" &&
|
|
306
|
+
value !== null &&
|
|
307
|
+
Symbol.asyncIterator in value &&
|
|
308
|
+
typeof value[Symbol.asyncIterator] === "function"
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function instrumentHttpSseConsumption(
|
|
313
|
+
value: AsyncIterable<SseMessage>,
|
|
314
|
+
recorder: NonNullable<ReturnType<typeof getTraceRecorder>>,
|
|
315
|
+
args: unknown[],
|
|
316
|
+
diagnostics: RequestDiagnostics,
|
|
317
|
+
): AsyncIterable<SseMessage> {
|
|
318
|
+
const source = value;
|
|
319
|
+
return {
|
|
320
|
+
async *[Symbol.asyncIterator]() {
|
|
321
|
+
try {
|
|
322
|
+
for await (const event of source) yield event;
|
|
323
|
+
} catch (error) {
|
|
324
|
+
const sanitizedError = sanitizeRequestError(error, diagnostics);
|
|
325
|
+
return await recorder.runSpan(
|
|
326
|
+
"http.sse.consume",
|
|
327
|
+
() => {
|
|
328
|
+
throw sanitizedError;
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
onError: (spanError) =>
|
|
332
|
+
buildSpanAttributes("http", "sse", args, undefined, spanError, diagnostics),
|
|
333
|
+
},
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
},
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
|
|
104
340
|
function getMethod(
|
|
105
341
|
namespace: InstrumentedNamespace,
|
|
106
342
|
methodName: string,
|
|
107
343
|
args: unknown[],
|
|
108
344
|
): string | undefined {
|
|
109
345
|
if (namespace === "http") {
|
|
346
|
+
// Preserve the original instrumentation contract: generic entry points are
|
|
347
|
+
// reported as REQUEST/STREAM/SSE, independent of transport options.
|
|
110
348
|
return methodName.toUpperCase();
|
|
111
349
|
}
|
|
112
350
|
|
|
113
351
|
if (namespace === "stealth") {
|
|
114
|
-
const options =
|
|
115
|
-
typeof args[1] === "object" && args[1] !== null ? args[1] : undefined;
|
|
352
|
+
const options = typeof args[1] === "object" && args[1] !== null ? args[1] : undefined;
|
|
116
353
|
if (options && "method" in options && typeof options.method === "string") {
|
|
117
354
|
return options.method.toUpperCase();
|
|
118
355
|
}
|
|
@@ -129,27 +366,34 @@ function buildSpanAttributes(
|
|
|
129
366
|
args: unknown[],
|
|
130
367
|
result?: unknown,
|
|
131
368
|
error?: unknown,
|
|
369
|
+
diagnostics: RequestDiagnostics = { sensitiveParamNames: [], sensitiveValues: [] },
|
|
132
370
|
): Record<string, string | number | boolean> {
|
|
133
371
|
const attributes: Record<string, string | number | boolean> = {};
|
|
134
|
-
const
|
|
372
|
+
const rawUrl = getUrl(namespace, args, result);
|
|
373
|
+
const structuralUrl = diagnostics.traceUrl ?? rawUrl;
|
|
374
|
+
const url = structuralUrl
|
|
375
|
+
? redactSensitiveText(
|
|
376
|
+
structuralUrl,
|
|
377
|
+
diagnostics.sensitiveValues,
|
|
378
|
+
diagnostics.serializedUrl?.requestUrl,
|
|
379
|
+
diagnostics.serializedUrl?.redactedUrl,
|
|
380
|
+
)
|
|
381
|
+
: undefined;
|
|
135
382
|
const method = getMethod(namespace, methodName, args);
|
|
136
|
-
const status = error
|
|
137
|
-
? getErrorStatus(error)
|
|
138
|
-
: getResponseStatus(namespace, result);
|
|
383
|
+
const status = error ? getErrorStatus(error) : getResponseStatus(namespace, result);
|
|
139
384
|
const duration = error ? undefined : getResponseDuration(result);
|
|
140
385
|
|
|
141
386
|
if (url) {
|
|
142
387
|
attributes.url = url;
|
|
143
388
|
}
|
|
389
|
+
if (diagnostics.requestId) attributes.request_id = diagnostics.requestId;
|
|
390
|
+
if (diagnostics.diagnosticUrlDegraded) attributes.redaction_degraded = true;
|
|
144
391
|
|
|
145
392
|
if (method) {
|
|
146
393
|
attributes.method = method;
|
|
147
394
|
}
|
|
148
395
|
|
|
149
|
-
if (
|
|
150
|
-
status !== undefined &&
|
|
151
|
-
(namespace === "http" || namespace === "stealth")
|
|
152
|
-
) {
|
|
396
|
+
if (status !== undefined && (namespace === "http" || namespace === "stealth")) {
|
|
153
397
|
attributes.status = status;
|
|
154
398
|
}
|
|
155
399
|
|
|
@@ -168,6 +412,64 @@ function buildSpanAttributes(
|
|
|
168
412
|
return attributes;
|
|
169
413
|
}
|
|
170
414
|
|
|
415
|
+
function isStealthRedirectRunResult(value: unknown): value is StealthRedirectRunResult {
|
|
416
|
+
return (
|
|
417
|
+
typeof value === "object" &&
|
|
418
|
+
value !== null &&
|
|
419
|
+
"reason" in value &&
|
|
420
|
+
typeof value.reason === "string" &&
|
|
421
|
+
"hops" in value &&
|
|
422
|
+
Array.isArray(value.hops) &&
|
|
423
|
+
"final" in value &&
|
|
424
|
+
typeof value.final === "object" &&
|
|
425
|
+
value.final !== null
|
|
426
|
+
);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
function buildStealthRedirectAttributes(
|
|
430
|
+
args: unknown[],
|
|
431
|
+
result: unknown,
|
|
432
|
+
error: unknown,
|
|
433
|
+
diagnostics: RequestDiagnostics,
|
|
434
|
+
): Record<string, string | number | boolean> {
|
|
435
|
+
const attributes = buildSpanAttributes("stealth", "fetch", args, undefined, error, diagnostics);
|
|
436
|
+
if (!isStealthRedirectRunResult(result)) return attributes;
|
|
437
|
+
|
|
438
|
+
attributes.redirect_reason = result.reason;
|
|
439
|
+
attributes.redirect_hop_count = result.hops.length;
|
|
440
|
+
attributes.status = result.final.status;
|
|
441
|
+
if (result.hops.length > 0) {
|
|
442
|
+
const sensitiveValues = new Set(diagnostics.sensitiveValues);
|
|
443
|
+
const path = result.hops
|
|
444
|
+
.map((hop) => {
|
|
445
|
+
const hopUrl = hop.nextUrl ?? hop.url;
|
|
446
|
+
const responseSensitiveParamNames = [...queryParamNames(hopUrl)].filter(isSensitiveKey);
|
|
447
|
+
const structural = redactUrlQueryParams(hopUrl, [
|
|
448
|
+
...new Set([...diagnostics.sensitiveParamNames, ...responseSensitiveParamNames]),
|
|
449
|
+
]);
|
|
450
|
+
for (const value of structural.sensitiveValues) sensitiveValues.add(value);
|
|
451
|
+
const safeUrl = redactSensitiveText(structural.redactedUrl, [...sensitiveValues]);
|
|
452
|
+
return `${hop.method} ${hop.status} ${safeUrl}`;
|
|
453
|
+
})
|
|
454
|
+
.join(" -> ");
|
|
455
|
+
attributes.redirect_path = redactSensitiveText(
|
|
456
|
+
path,
|
|
457
|
+
[...sensitiveValues],
|
|
458
|
+
diagnostics.serializedUrl?.requestUrl,
|
|
459
|
+
diagnostics.serializedUrl?.redactedUrl,
|
|
460
|
+
);
|
|
461
|
+
}
|
|
462
|
+
return attributes;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
function queryParamNames(url: string): Set<string> {
|
|
466
|
+
const queryStart = url.indexOf("?");
|
|
467
|
+
if (queryStart === -1) return new Set();
|
|
468
|
+
const fragmentStart = url.indexOf("#", queryStart);
|
|
469
|
+
const query = url.slice(queryStart + 1, fragmentStart === -1 ? undefined : fragmentStart);
|
|
470
|
+
return new Set(new URLSearchParams(query).keys());
|
|
471
|
+
}
|
|
472
|
+
|
|
171
473
|
function getBrowserPageAttributes(
|
|
172
474
|
methodName: string,
|
|
173
475
|
args: unknown[],
|
|
@@ -241,10 +543,8 @@ function wrapPage<T extends object>(page: T, trace: TraceContext): T {
|
|
|
241
543
|
return result;
|
|
242
544
|
},
|
|
243
545
|
{
|
|
244
|
-
onSuccess: () =>
|
|
245
|
-
|
|
246
|
-
onError: (error) =>
|
|
247
|
-
getBrowserPageAttributes(methodName, args, undefined, error),
|
|
546
|
+
onSuccess: () => getBrowserPageAttributes(methodName, args, elapsedMs),
|
|
547
|
+
onError: (error) => getBrowserPageAttributes(methodName, args, undefined, error),
|
|
248
548
|
},
|
|
249
549
|
);
|
|
250
550
|
};
|
|
@@ -255,10 +555,65 @@ function wrapPage<T extends object>(page: T, trace: TraceContext): T {
|
|
|
255
555
|
});
|
|
256
556
|
}
|
|
257
557
|
|
|
558
|
+
function wrapStealthRedirects(
|
|
559
|
+
redirects: StealthSession["redirects"],
|
|
560
|
+
trace: TraceContext,
|
|
561
|
+
): StealthSession["redirects"] {
|
|
562
|
+
const recorder = getTraceRecorder(trace);
|
|
563
|
+
if (!recorder) return redirects;
|
|
564
|
+
|
|
565
|
+
return {
|
|
566
|
+
run(...args: Parameters<StealthSession["redirects"]["run"]>) {
|
|
567
|
+
const diagnosticArgs = [args[0].url, args[0]];
|
|
568
|
+
const diagnostics = snapshotRequestDiagnostics("stealth", "fetch", diagnosticArgs);
|
|
569
|
+
let result: ReturnType<StealthSession["redirects"]["run"]>;
|
|
570
|
+
try {
|
|
571
|
+
result = redirects.run(...args);
|
|
572
|
+
} catch (error) {
|
|
573
|
+
const sanitizedError = sanitizeRequestError(error, diagnostics);
|
|
574
|
+
recorder
|
|
575
|
+
.runSpan(
|
|
576
|
+
"stealth.redirects.run",
|
|
577
|
+
() => {
|
|
578
|
+
throw sanitizedError;
|
|
579
|
+
},
|
|
580
|
+
{
|
|
581
|
+
onError: (spanError) =>
|
|
582
|
+
buildStealthRedirectAttributes(diagnosticArgs, undefined, spanError, diagnostics),
|
|
583
|
+
},
|
|
584
|
+
)
|
|
585
|
+
.catch(() => undefined);
|
|
586
|
+
throw sanitizedError;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
const sanitizedResult = Promise.resolve(result).catch((error: unknown) => {
|
|
590
|
+
throw sanitizeRequestError(error, diagnostics);
|
|
591
|
+
});
|
|
592
|
+
return recorder.runSpan("stealth.redirects.run", () => sanitizedResult, {
|
|
593
|
+
onSuccess: (spanResult) =>
|
|
594
|
+
buildStealthRedirectAttributes(diagnosticArgs, spanResult, undefined, diagnostics),
|
|
595
|
+
onError: (error) =>
|
|
596
|
+
buildStealthRedirectAttributes(diagnosticArgs, undefined, error, diagnostics),
|
|
597
|
+
});
|
|
598
|
+
},
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
function wrapStealthSession(session: StealthSession, trace: TraceContext): StealthSession {
|
|
603
|
+
const wrappedSession = wrapNamespace("stealth", session, trace);
|
|
604
|
+
const redirects = wrapStealthRedirects(session.redirects, trace);
|
|
605
|
+
return new Proxy(wrappedSession, {
|
|
606
|
+
get(target, property, receiver) {
|
|
607
|
+
return property === "redirects" ? redirects : Reflect.get(target, property, receiver);
|
|
608
|
+
},
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
|
|
258
612
|
function wrapNamespace<T extends object>(
|
|
259
613
|
namespace: InstrumentedNamespace,
|
|
260
614
|
target: T,
|
|
261
615
|
trace: TraceContext,
|
|
616
|
+
shouldInstrument?: (methodName: string, args: unknown[]) => boolean,
|
|
262
617
|
): T {
|
|
263
618
|
const recorder = getTraceRecorder(trace);
|
|
264
619
|
if (!recorder) {
|
|
@@ -310,18 +665,14 @@ function wrapNamespace<T extends object>(
|
|
|
310
665
|
namespaceTarget &&
|
|
311
666
|
typeof namespaceTarget === "object" &&
|
|
312
667
|
"engine" in namespaceTarget &&
|
|
313
|
-
typeof (namespaceTarget as { engine?: unknown }).engine ===
|
|
314
|
-
"string"
|
|
668
|
+
typeof (namespaceTarget as { engine?: unknown }).engine === "string"
|
|
315
669
|
) {
|
|
316
|
-
attributes.engine = (
|
|
317
|
-
namespaceTarget as { engine: string }
|
|
318
|
-
).engine;
|
|
670
|
+
attributes.engine = (namespaceTarget as { engine: string }).engine;
|
|
319
671
|
}
|
|
320
672
|
|
|
321
673
|
return attributes;
|
|
322
674
|
},
|
|
323
|
-
onError: (error) =>
|
|
324
|
-
getBrowserPageAttributes("newPage", args, undefined, error),
|
|
675
|
+
onError: (error) => getBrowserPageAttributes("newPage", args, undefined, error),
|
|
325
676
|
},
|
|
326
677
|
);
|
|
327
678
|
};
|
|
@@ -348,10 +699,8 @@ function wrapNamespace<T extends object>(
|
|
|
348
699
|
return result;
|
|
349
700
|
},
|
|
350
701
|
{
|
|
351
|
-
onSuccess: () =>
|
|
352
|
-
|
|
353
|
-
onError: (error) =>
|
|
354
|
-
getBrowserPageAttributes(methodName, args, undefined, error),
|
|
702
|
+
onSuccess: () => getBrowserPageAttributes(methodName, args, elapsedMs),
|
|
703
|
+
onError: (error) => getBrowserPageAttributes(methodName, args, undefined, error),
|
|
355
704
|
},
|
|
356
705
|
);
|
|
357
706
|
};
|
|
@@ -360,23 +709,103 @@ function wrapNamespace<T extends object>(
|
|
|
360
709
|
return wrapped;
|
|
361
710
|
}
|
|
362
711
|
|
|
363
|
-
const wrapped = (...args: unknown[]) =>
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
712
|
+
const wrapped = (...args: unknown[]) => {
|
|
713
|
+
if (shouldInstrument && !shouldInstrument(methodName, args)) {
|
|
714
|
+
return Reflect.apply(value, namespaceTarget, args);
|
|
715
|
+
}
|
|
716
|
+
const requestDiagnostics = snapshotRequestDiagnostics(namespace, methodName, args);
|
|
717
|
+
// Invoke first and decide by the RETURN VALUE. `runSpan` always
|
|
718
|
+
// returns a Promise, so unconditionally span-wrapping every member
|
|
719
|
+
// silently rewrote synchronous contracts: `ctx.state.namespace()`
|
|
720
|
+
// (a sync factory) came back as a Promise, and every method call on
|
|
721
|
+
// it threw a raw TypeError — surfaced in production as catchtable's
|
|
722
|
+
// deterministic CONFIRM_STATE_UNAVAILABLE on 2026-07-27 (and the
|
|
723
|
+
// 2026-07-22 reserve internal_error loop before it). Sync members
|
|
724
|
+
// keep their sync contract; only genuinely async operations are
|
|
725
|
+
// recorded as spans.
|
|
726
|
+
let result: unknown;
|
|
727
|
+
try {
|
|
728
|
+
result = Reflect.apply(value, namespaceTarget, args);
|
|
729
|
+
} catch (error) {
|
|
730
|
+
const sanitizedError = sanitizeRequestError(error, requestDiagnostics);
|
|
731
|
+
// A promise-returning implementation may still throw
|
|
732
|
+
// SYNCHRONOUSLY during pre-flight validation. Preserve the
|
|
733
|
+
// synchronous throw contract, but keep recording the failure
|
|
734
|
+
// span (the pre-fidelity wrapper captured these).
|
|
735
|
+
recorder
|
|
736
|
+
.runSpan(
|
|
737
|
+
`${namespace}.${methodName}`,
|
|
738
|
+
() => {
|
|
739
|
+
throw sanitizedError;
|
|
740
|
+
},
|
|
741
|
+
{
|
|
742
|
+
onError: (spanError) =>
|
|
743
|
+
buildSpanAttributes(
|
|
744
|
+
namespace,
|
|
745
|
+
methodName,
|
|
746
|
+
args,
|
|
747
|
+
undefined,
|
|
748
|
+
spanError,
|
|
749
|
+
requestDiagnostics,
|
|
750
|
+
),
|
|
751
|
+
},
|
|
752
|
+
)
|
|
753
|
+
.catch(() => undefined);
|
|
754
|
+
throw sanitizedError;
|
|
755
|
+
}
|
|
756
|
+
if (!isThenable(result)) {
|
|
757
|
+
// The state namespace factory returns the object whose METHODS
|
|
758
|
+
// are the operations worth tracing — instrument that object so
|
|
759
|
+
// `state.get`/`state.compareAndSet`/… spans exist (they never
|
|
760
|
+
// could before: the factory's return value was destroyed).
|
|
761
|
+
if (
|
|
762
|
+
namespace === "state" &&
|
|
763
|
+
methodName === "namespace" &&
|
|
764
|
+
typeof result === "object" &&
|
|
765
|
+
result !== null
|
|
766
|
+
) {
|
|
767
|
+
return wrapNamespace(namespace, result, trace);
|
|
768
|
+
}
|
|
769
|
+
if (
|
|
770
|
+
namespace === "stealth" &&
|
|
771
|
+
methodName === "createSession" &&
|
|
772
|
+
typeof result === "object" &&
|
|
773
|
+
result !== null
|
|
774
|
+
) {
|
|
775
|
+
return wrapStealthSession(result as StealthSession, trace);
|
|
776
|
+
}
|
|
777
|
+
return result;
|
|
778
|
+
}
|
|
779
|
+
const sanitizedResult = Promise.resolve(result).catch((error: unknown) => {
|
|
780
|
+
throw sanitizeRequestError(error, requestDiagnostics);
|
|
781
|
+
});
|
|
782
|
+
const tracedResult = recorder.runSpan(`${namespace}.${methodName}`, () => sanitizedResult, {
|
|
783
|
+
onSuccess: (spanResult) =>
|
|
784
|
+
buildSpanAttributes(
|
|
785
|
+
namespace,
|
|
786
|
+
methodName,
|
|
787
|
+
args,
|
|
788
|
+
spanResult,
|
|
789
|
+
undefined,
|
|
790
|
+
requestDiagnostics,
|
|
791
|
+
),
|
|
792
|
+
onError: (error) =>
|
|
793
|
+
buildSpanAttributes(namespace, methodName, args, undefined, error, requestDiagnostics),
|
|
794
|
+
});
|
|
795
|
+
return namespace === "http" && methodName === "stream"
|
|
796
|
+
? tracedResult.then((spanResult) =>
|
|
797
|
+
isHttpStreamResponse(spanResult)
|
|
798
|
+
? instrumentHttpStreamConsumption(spanResult, recorder, args, requestDiagnostics)
|
|
799
|
+
: spanResult,
|
|
800
|
+
)
|
|
801
|
+
: namespace === "http" && methodName === "sse"
|
|
802
|
+
? tracedResult.then((spanResult) =>
|
|
803
|
+
isAsyncIterable<SseMessage>(spanResult)
|
|
804
|
+
? instrumentHttpSseConsumption(spanResult, recorder, args, requestDiagnostics)
|
|
805
|
+
: spanResult,
|
|
806
|
+
)
|
|
807
|
+
: tracedResult;
|
|
808
|
+
};
|
|
380
809
|
|
|
381
810
|
wrappedMethods.set(property, wrapped);
|
|
382
811
|
return wrapped;
|