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