@apifuse/provider-sdk 2.2.0-beta.61 → 2.2.0-beta.63
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 +268 -9
- package/CHANGELOG.md +8 -0
- package/README.md +1 -0
- package/bin/apifuse-check.ts +84 -2
- package/bin/apifuse-dev.ts +11 -31
- package/bin/apifuse-migrate-deployment.ts +200 -0
- package/bin/apifuse-pack-check.ts +11 -4
- package/bin/apifuse-pack-types.ts +191 -4
- package/bin/apifuse-record.ts +44 -32
- package/bin/apifuse-test.ts +3 -1
- package/dist/cli/commands.d.ts +1 -1
- package/dist/cli/commands.js +11 -0
- package/dist/cli/deployment-intent.d.ts +178 -0
- package/dist/cli/deployment-intent.js +277 -0
- package/dist/cli/migrate-deployment-intent.d.ts +132 -0
- package/dist/cli/migrate-deployment-intent.js +1552 -0
- package/dist/cli/migrate-provider-shape.d.ts +5 -1
- package/dist/cli/migrate-provider-shape.js +4 -2
- package/dist/cli/resolver-runtime.d.ts +21 -0
- package/dist/cli/resolver-runtime.js +31 -0
- package/dist/define.d.ts +3 -0
- package/dist/define.js +5 -0
- package/dist/dev.d.ts +3 -1
- package/dist/dev.js +6 -1
- package/dist/engine.d.ts +35 -1
- package/dist/engine.js +21 -2
- package/dist/error-resolution.d.ts +1 -0
- package/dist/error-resolution.js +54 -0
- package/dist/errors.d.ts +39 -1
- package/dist/errors.js +50 -0
- package/dist/handle-meta.d.ts +18 -2
- package/dist/handle-meta.js +30 -2
- package/dist/handle.d.ts +33 -12
- package/dist/handle.js +69 -24
- package/dist/i18n/error-messages.d.ts +86 -0
- package/dist/i18n/error-messages.js +192 -0
- package/dist/i18n/index.d.ts +1 -0
- package/dist/i18n/index.js +1 -0
- package/dist/i18n/keys.d.ts +12 -0
- package/dist/i18n/keys.js +76 -5
- package/dist/index.d.ts +10 -2
- package/dist/index.js +9 -1
- package/dist/lint.d.ts +10 -0
- package/dist/lint.js +440 -57
- package/dist/provider.d.ts +7 -5
- package/dist/provider.js +4 -2
- package/dist/runtime/browser-telemetry-binding.d.ts +5 -0
- package/dist/runtime/browser-telemetry-binding.js +83 -0
- package/dist/runtime/browser-telemetry.d.ts +76 -0
- package/dist/runtime/browser-telemetry.js +165 -0
- package/dist/runtime/browser.d.ts +3 -0
- package/dist/runtime/browser.js +208 -47
- package/dist/runtime/cache-telemetry.d.ts +71 -0
- package/dist/runtime/cache-telemetry.js +177 -0
- package/dist/runtime/cache.js +67 -7
- package/dist/runtime/capability-response.d.ts +3 -0
- package/dist/runtime/capability-response.js +56 -0
- package/dist/runtime/capability-telemetry.d.ts +46 -0
- package/dist/runtime/capability-telemetry.js +68 -0
- package/dist/runtime/diagnostic-env.d.ts +3 -0
- package/dist/runtime/diagnostic-env.js +10 -1
- package/dist/runtime/engine-mode.d.ts +74 -0
- package/dist/runtime/engine-mode.js +152 -0
- package/dist/runtime/handle.js +15 -10
- package/dist/runtime/http-telemetry-binding.d.ts +10 -0
- package/dist/runtime/http-telemetry-binding.js +152 -0
- package/dist/runtime/http-telemetry-guard.d.ts +16 -0
- package/dist/runtime/http-telemetry-guard.js +202 -0
- package/dist/runtime/http-telemetry.d.ts +104 -0
- package/dist/runtime/http-telemetry.js +190 -0
- package/dist/runtime/http.d.ts +31 -0
- package/dist/runtime/http.js +356 -174
- package/dist/runtime/instrumentation.js +92 -13
- package/dist/runtime/ocr-telemetry.d.ts +82 -0
- package/dist/runtime/ocr-telemetry.js +192 -0
- package/dist/runtime/ocr.js +30 -8
- package/dist/runtime/request-telemetry.d.ts +2 -0
- package/dist/runtime/request-telemetry.js +2 -1
- package/dist/runtime/resolver-runtime-options.d.ts +14 -0
- package/dist/runtime/resolver-runtime-options.js +33 -0
- package/dist/runtime/resolver-shared.d.ts +3 -2
- package/dist/runtime/resolver-shared.js +4 -4
- package/dist/runtime/resolver-telemetry.d.ts +1 -0
- package/dist/runtime/resolver-telemetry.js +1 -1
- package/dist/runtime/resolver-vendors/browser.d.ts +2 -0
- package/dist/runtime/resolver-vendors/browser.js +46 -0
- package/dist/runtime/resolver-vendors/hosts.d.ts +21 -0
- package/dist/runtime/resolver-vendors/hosts.js +35 -0
- package/dist/runtime/resolver-vendors/hypersolutions.js +2 -2
- package/dist/runtime/resolver-vendors/types.d.ts +5 -4
- package/dist/runtime/resolver.d.ts +4 -1
- package/dist/runtime/resolver.js +46 -13
- package/dist/runtime/state-telemetry.d.ts +79 -0
- package/dist/runtime/state-telemetry.js +194 -0
- package/dist/runtime/state.d.ts +3 -0
- package/dist/runtime/state.js +26 -7
- package/dist/runtime/stealth-cookies.d.ts +5 -1
- package/dist/runtime/stealth-cookies.js +21 -1
- package/dist/runtime/stealth-owned-headers.d.ts +26 -0
- package/dist/runtime/stealth-owned-headers.js +37 -0
- package/dist/runtime/stealth-telemetry.d.ts +92 -0
- package/dist/runtime/stealth-telemetry.js +179 -0
- package/dist/runtime/stealth.d.ts +4 -1
- package/dist/runtime/stealth.js +228 -85
- package/dist/runtime/stt-telemetry.d.ts +77 -0
- package/dist/runtime/stt-telemetry.js +176 -0
- package/dist/runtime/stt.js +15 -6
- package/dist/server/error-stack-frames.d.ts +35 -0
- package/dist/server/error-stack-frames.js +219 -0
- package/dist/server/index.d.ts +9 -0
- package/dist/server/index.js +5 -0
- package/dist/server/sdk-version.d.ts +3 -0
- package/dist/server/sdk-version.js +19 -0
- package/dist/server/self-test.js +1 -18
- package/dist/server/sensitive-values.d.ts +1 -1
- package/dist/server/sensitive-values.js +9 -0
- package/dist/server/serve-implementation.d.ts +53 -2
- package/dist/server/serve-implementation.js +369 -123
- package/dist/server/types.d.ts +1 -0
- package/dist/server/types.js +7 -0
- package/dist/stateful/stateful-provider-owner-forwarder.js +22 -0
- package/dist/stateful/stateful-provider-runtime-context.d.ts +3 -0
- package/dist/stateful/stateful-provider-runtime-context.js +1 -0
- package/dist/types.d.ts +94 -1
- package/package.json +6 -1
- package/src/cli/commands.ts +14 -0
- package/src/cli/deployment-intent.ts +364 -0
- package/src/cli/migrate-deployment-intent.ts +1908 -0
- package/src/cli/migrate-provider-shape.ts +10 -4
- package/src/cli/resolver-runtime.ts +72 -0
- package/src/define.ts +13 -0
- package/src/dev.ts +9 -2
- package/src/engine.ts +38 -2
- package/src/error-resolution.ts +58 -0
- package/src/errors.ts +77 -1
- package/src/handle-meta.ts +39 -4
- package/src/handle.ts +121 -38
- package/src/i18n/error-messages.ts +255 -0
- package/src/i18n/index.ts +1 -0
- package/src/i18n/keys.ts +80 -6
- package/src/index.ts +91 -0
- package/src/lint.ts +552 -57
- package/src/provider.ts +20 -0
- package/src/runtime/browser-telemetry-binding.ts +92 -0
- package/src/runtime/browser-telemetry.ts +289 -0
- package/src/runtime/browser.ts +249 -65
- package/src/runtime/cache-telemetry.ts +247 -0
- package/src/runtime/cache.ts +68 -17
- package/src/runtime/capability-response.ts +53 -0
- package/src/runtime/capability-telemetry.ts +101 -0
- package/src/runtime/diagnostic-env.ts +11 -1
- package/src/runtime/engine-mode.ts +233 -0
- package/src/runtime/handle.ts +20 -10
- package/src/runtime/http-telemetry-binding.ts +162 -0
- package/src/runtime/http-telemetry-guard.ts +208 -0
- package/src/runtime/http-telemetry.ts +292 -0
- package/src/runtime/http.ts +457 -204
- package/src/runtime/instrumentation.ts +105 -16
- package/src/runtime/ocr-telemetry.ts +308 -0
- package/src/runtime/ocr.ts +109 -74
- package/src/runtime/request-telemetry.ts +2 -1
- package/src/runtime/resolver-runtime-options.ts +50 -0
- package/src/runtime/resolver-shared.ts +9 -4
- package/src/runtime/resolver-telemetry.ts +1 -1
- package/src/runtime/resolver-vendors/browser.ts +65 -7
- package/src/runtime/resolver-vendors/hosts.ts +43 -0
- package/src/runtime/resolver-vendors/hypersolutions.ts +2 -2
- package/src/runtime/resolver-vendors/types.ts +5 -4
- package/src/runtime/resolver.ts +64 -21
- package/src/runtime/state-telemetry.ts +298 -0
- package/src/runtime/state.ts +46 -45
- package/src/runtime/stealth-cookies.ts +24 -1
- package/src/runtime/stealth-owned-headers.ts +41 -0
- package/src/runtime/stealth-telemetry.ts +304 -0
- package/src/runtime/stealth.ts +355 -150
- package/src/runtime/stt-telemetry.ts +282 -0
- package/src/runtime/stt.ts +93 -71
- package/src/server/error-stack-frames.ts +214 -0
- package/src/server/index.ts +66 -0
- package/src/server/sdk-version.ts +22 -0
- package/src/server/self-test.ts +1 -21
- package/src/server/sensitive-values.ts +14 -0
- package/src/server/serve-implementation.ts +601 -157
- package/src/server/types.ts +7 -0
- package/src/stateful/stateful-provider-owner-forwarder.ts +23 -0
- package/src/stateful/stateful-provider-runtime-context.ts +4 -0
- package/src/types.ts +99 -1
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/approval-override.ts.txt +0 -6
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/codemod-syntax.ts.txt +0 -3
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/connection-precedence.ts.txt +0 -10
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-ambiguous-a.ts.txt +0 -3
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-ambiguous-b.ts.txt +0 -3
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-ambiguous-barrel.ts.txt +0 -2
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-ambiguous-index.ts.txt +0 -3
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-computed.ts.txt +0 -6
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-cycle-a.ts.txt +0 -1
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-cycle-b.ts.txt +0 -1
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-cycle-index.ts.txt +0 -3
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-barrel.ts.txt +0 -7
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-catalog.ts.txt +0 -19
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-docs.ts.txt +0 -6
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-index.ts.txt +0 -3
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-stores.ts.txt +0 -8
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-indirect-config.ts.txt +0 -5
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-nonstatic.ts.txt +0 -4
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-package-index.ts.txt +0 -3
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-reexport-index.ts.txt +0 -3
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-reexport-leaf.ts.txt +0 -10
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-reexport-one.ts.txt +0 -1
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-reexport-two.ts.txt +0 -1
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-composed-index.ts.txt +0 -3
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-composed-one.ts.txt +0 -6
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-composed-two.ts.txt +0 -6
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-mixed-index.ts.txt +0 -14
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-registry.ts.txt +0 -3
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-star-package-barrel.ts.txt +0 -2
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-star-package-index.ts.txt +0 -3
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-star-package-leaf.ts.txt +0 -3
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/docs-conflict.ts.txt +0 -8
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-hoisted-array-spread.ts.txt +0 -15
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-imported-array-spread.ts.txt +0 -9
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-kebab-operation-id.ts.txt +0 -17
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-map.ts.txt +0 -5
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-mixed-array-spread.ts.txt +0 -24
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-operation.ts.txt +0 -16
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-snake-operation-id.ts.txt +0 -21
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-duplicate-provider.ts.txt +0 -11
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-id-unresolved.ts.txt +0 -7
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-map.ts.txt +0 -3
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-one-to-many.ts.txt +0 -18
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-one-to-one.ts.txt +0 -13
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/hoist-all.ts.txt +0 -31
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/hoisted-const.ts.txt +0 -11
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/imported-spread.ts.txt +0 -11
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-map.ts.txt +0 -11
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-cast-tail.ts.txt +0 -21
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-ekitan.ts.txt +0 -11
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-override.ts.txt +0 -14
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/locale-canonical-en.json +0 -1
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/locale-canonical-ja.json +0 -1
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/locale-canonical-ko.json +0 -1
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/locale-existing-operation-namespace-en.json +0 -8
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/missing-english-locale.ts.txt +0 -7
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/no-safety.ts.txt +0 -6
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/non-literal.ts.txt +0 -7
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/redundant-approval.ts.txt +0 -6
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-binding-ambiguous.ts.txt +0 -12
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-imported-other.ts.txt +0 -7
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-imported.ts.txt +0 -5
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-key-ambiguous.ts.txt +0 -19
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-shorthand.ts.txt +0 -9
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-typed.ts.txt +0 -11
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-unrelated.ts.txt +0 -13
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/safety-conflict.ts.txt +0 -7
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/stream.ts.txt +0 -7
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/tool-router-spread.ts.txt +0 -15
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/unparseable.ts.txt +0 -4
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/verbatim-template.ts.txt +0 -12
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { Buffer } from "node:buffer";
|
|
2
|
+
import { closedEnum } from "./request-telemetry.js";
|
|
3
|
+
const MAX_ATTEMPT_SAMPLES = 24;
|
|
4
|
+
const MAX_DIAGNOSTIC_TEXT = 300;
|
|
5
|
+
function boundedInteger(value) {
|
|
6
|
+
if (!Number.isFinite(value))
|
|
7
|
+
return Number.MAX_SAFE_INTEGER;
|
|
8
|
+
return Math.min(Number.MAX_SAFE_INTEGER, Math.max(0, Math.floor(value)));
|
|
9
|
+
}
|
|
10
|
+
function saturatingAdd(a, b) {
|
|
11
|
+
if (!Number.isFinite(a) || !Number.isFinite(b))
|
|
12
|
+
return Number.MAX_SAFE_INTEGER;
|
|
13
|
+
return Math.min(Number.MAX_SAFE_INTEGER, boundedInteger(a) + boundedInteger(b));
|
|
14
|
+
}
|
|
15
|
+
function boundedText(value, redact) {
|
|
16
|
+
let result = value;
|
|
17
|
+
try {
|
|
18
|
+
result = redact?.(value) ?? value;
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
result = "[REDACTION_FAILED]";
|
|
22
|
+
}
|
|
23
|
+
const length = Math.min(result.length, MAX_DIAGNOSTIC_TEXT);
|
|
24
|
+
const units = Buffer.alloc(length * 2);
|
|
25
|
+
for (let index = 0; index < length; index += 1) {
|
|
26
|
+
units.writeUInt16LE(result.charCodeAt(index), index * 2);
|
|
27
|
+
}
|
|
28
|
+
return units.toString("utf16le");
|
|
29
|
+
}
|
|
30
|
+
function cloneDiagnostics(diagnostics, redact) {
|
|
31
|
+
if (!diagnostics)
|
|
32
|
+
return undefined;
|
|
33
|
+
const result = {
|
|
34
|
+
...(diagnostics.name === undefined ? {} : { name: boundedText(diagnostics.name, redact) }),
|
|
35
|
+
...(diagnostics.message === undefined
|
|
36
|
+
? {}
|
|
37
|
+
: { message: boundedText(diagnostics.message, redact) }),
|
|
38
|
+
...(diagnostics.code === undefined ? {} : { code: boundedText(diagnostics.code, redact) }),
|
|
39
|
+
};
|
|
40
|
+
return Object.keys(result).length > 0 ? result : undefined;
|
|
41
|
+
}
|
|
42
|
+
function cloneProfile(profile) {
|
|
43
|
+
return { browser: profile.browser, os: profile.os };
|
|
44
|
+
}
|
|
45
|
+
export class StealthTelemetryCollector {
|
|
46
|
+
key = "stealth";
|
|
47
|
+
#redact;
|
|
48
|
+
#attempts = 0;
|
|
49
|
+
#poolRefreshes = 0;
|
|
50
|
+
#redirectHops = 0;
|
|
51
|
+
#profileId;
|
|
52
|
+
#proxyUsed = false;
|
|
53
|
+
#requestClass;
|
|
54
|
+
#sbsdDetected;
|
|
55
|
+
#sbsdOutcome;
|
|
56
|
+
#safeRefetch = 0;
|
|
57
|
+
#lastStatus;
|
|
58
|
+
#ms = 0;
|
|
59
|
+
#attemptSamples = [];
|
|
60
|
+
#attemptSamplesDropped = 0;
|
|
61
|
+
constructor(options = {}) {
|
|
62
|
+
this.#redact = options.redact;
|
|
63
|
+
}
|
|
64
|
+
recordAttempt(event) {
|
|
65
|
+
const ms = boundedInteger(event.ms);
|
|
66
|
+
this.#attempts = saturatingAdd(this.#attempts, 1);
|
|
67
|
+
this.#ms = saturatingAdd(this.#ms, ms);
|
|
68
|
+
this.#profileId = cloneProfile(event.profileId);
|
|
69
|
+
this.#proxyUsed ||= event.proxyUsed;
|
|
70
|
+
this.#requestClass = event.requestClass;
|
|
71
|
+
if (event.status !== undefined)
|
|
72
|
+
this.#lastStatus = boundedInteger(event.status);
|
|
73
|
+
if (this.#attemptSamples.length >= MAX_ATTEMPT_SAMPLES) {
|
|
74
|
+
this.#attemptSamplesDropped = saturatingAdd(this.#attemptSamplesDropped, 1);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const sample = {
|
|
78
|
+
n: this.#attempts,
|
|
79
|
+
ms,
|
|
80
|
+
...(event.status === undefined ? {} : { status: boundedInteger(event.status) }),
|
|
81
|
+
...(event.errorCode === undefined ? {} : { e: event.errorCode }),
|
|
82
|
+
...(event.kind === undefined ? {} : { kind: event.kind }),
|
|
83
|
+
...(event.diagnostics
|
|
84
|
+
? { diagnostics: cloneDiagnostics(event.diagnostics, this.#redact) }
|
|
85
|
+
: {}),
|
|
86
|
+
};
|
|
87
|
+
if (sample.diagnostics === undefined)
|
|
88
|
+
delete sample.diagnostics;
|
|
89
|
+
this.#attemptSamples.push(sample);
|
|
90
|
+
}
|
|
91
|
+
recordPoolRefresh() {
|
|
92
|
+
this.#poolRefreshes = saturatingAdd(this.#poolRefreshes, 1);
|
|
93
|
+
}
|
|
94
|
+
recordRedirectHop() {
|
|
95
|
+
this.#redirectHops = saturatingAdd(this.#redirectHops, 1);
|
|
96
|
+
}
|
|
97
|
+
recordSbsd(event) {
|
|
98
|
+
if (typeof event === "string") {
|
|
99
|
+
this.#sbsdDetected = true;
|
|
100
|
+
this.#sbsdOutcome = event;
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (!event)
|
|
104
|
+
return;
|
|
105
|
+
this.#sbsdDetected = (this.#sbsdDetected ?? false) || event.detected;
|
|
106
|
+
if (event.outcome !== undefined)
|
|
107
|
+
this.#sbsdOutcome = event.outcome;
|
|
108
|
+
}
|
|
109
|
+
recordSafeRefetch() {
|
|
110
|
+
this.#safeRefetch = saturatingAdd(this.#safeRefetch, 1);
|
|
111
|
+
}
|
|
112
|
+
toLogPayload() {
|
|
113
|
+
if (this.#attempts === 0 &&
|
|
114
|
+
this.#poolRefreshes === 0 &&
|
|
115
|
+
this.#redirectHops === 0 &&
|
|
116
|
+
this.#safeRefetch === 0 &&
|
|
117
|
+
this.#sbsdDetected === undefined) {
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
attempts: this.#attempts,
|
|
122
|
+
poolRefreshes: this.#poolRefreshes,
|
|
123
|
+
redirectHops: this.#redirectHops,
|
|
124
|
+
...(this.#profileId ? { profileId: cloneProfile(this.#profileId) } : {}),
|
|
125
|
+
proxyUsed: this.#proxyUsed,
|
|
126
|
+
...(this.#requestClass ? { requestClass: this.#requestClass } : {}),
|
|
127
|
+
...(this.#sbsdDetected === undefined ? {} : { sbsdDetected: this.#sbsdDetected }),
|
|
128
|
+
...(this.#sbsdOutcome ? { sbsdOutcome: this.#sbsdOutcome } : {}),
|
|
129
|
+
safeRefetch: this.#safeRefetch,
|
|
130
|
+
...(this.#lastStatus === undefined ? {} : { lastStatus: this.#lastStatus }),
|
|
131
|
+
ms: this.#ms,
|
|
132
|
+
...(this.#attemptSamples.length > 0
|
|
133
|
+
? {
|
|
134
|
+
attemptSamples: this.#attemptSamples.map((sample) => ({
|
|
135
|
+
...sample,
|
|
136
|
+
...(sample.diagnostics
|
|
137
|
+
? {
|
|
138
|
+
diagnostics: { ...sample.diagnostics },
|
|
139
|
+
}
|
|
140
|
+
: {}),
|
|
141
|
+
})),
|
|
142
|
+
}
|
|
143
|
+
: {}),
|
|
144
|
+
...(this.#attemptSamplesDropped > 0
|
|
145
|
+
? { attemptSamplesDropped: this.#attemptSamplesDropped }
|
|
146
|
+
: {}),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
toHeaderPayload(log) {
|
|
150
|
+
const attemptSamples = log.attemptSamples?.map((sample) => ({
|
|
151
|
+
n: sample.n,
|
|
152
|
+
ms: sample.ms,
|
|
153
|
+
...(sample.status === undefined ? {} : { status: sample.status }),
|
|
154
|
+
...(sample.e ? { e: closedEnum(sample.e) } : {}),
|
|
155
|
+
...(sample.kind ? { kind: closedEnum(sample.kind) } : {}),
|
|
156
|
+
}));
|
|
157
|
+
return {
|
|
158
|
+
attempts: log.attempts,
|
|
159
|
+
poolRefreshes: log.poolRefreshes,
|
|
160
|
+
redirectHops: log.redirectHops,
|
|
161
|
+
...(log.profileId
|
|
162
|
+
? {
|
|
163
|
+
profileId: {
|
|
164
|
+
browser: closedEnum(log.profileId.browser),
|
|
165
|
+
os: closedEnum(log.profileId.os),
|
|
166
|
+
},
|
|
167
|
+
}
|
|
168
|
+
: {}),
|
|
169
|
+
proxyUsed: log.proxyUsed,
|
|
170
|
+
...(log.requestClass ? { requestClass: closedEnum(log.requestClass) } : {}),
|
|
171
|
+
...(log.sbsdDetected === undefined ? {} : { sbsdDetected: log.sbsdDetected }),
|
|
172
|
+
...(log.sbsdOutcome ? { sbsdOutcome: closedEnum(log.sbsdOutcome) } : {}),
|
|
173
|
+
safeRefetch: log.safeRefetch,
|
|
174
|
+
...(log.lastStatus === undefined ? {} : { lastStatus: log.lastStatus }),
|
|
175
|
+
ms: log.ms,
|
|
176
|
+
...(attemptSamples && attemptSamples.length > 0 ? { attemptSamples } : {}),
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import type { BrowserProfile, EmulationOS } from "wreq-js";
|
|
2
2
|
import type { ProxyResolutionOptions } from "../config/loader.js";
|
|
3
3
|
import type { StealthClient, StealthProfileDescriptor, StealthProfileSelection, StealthResponse } from "../types.js";
|
|
4
|
+
export type { StealthTelemetryAttemptEvent, StealthTelemetryAttemptKind, StealthTelemetryDiagnostics, StealthTelemetryErrorCode, StealthTelemetryRequestClass, StealthTelemetrySbsdEvent, StealthTelemetrySbsdOutcome, StealthTelemetrySink, } from "./stealth-telemetry.js";
|
|
5
|
+
import type { StealthTelemetrySink } from "./stealth-telemetry.js";
|
|
4
6
|
export declare const DEFAULT_STEALTH_PROFILE: StealthProfileDescriptor;
|
|
5
7
|
export type StealthClientOptions = ProxyResolutionOptions & {
|
|
8
|
+
/** Request-scoped stealth transport observations. */
|
|
9
|
+
stealthTelemetry?: StealthTelemetrySink;
|
|
6
10
|
warn?: (message: string) => void;
|
|
7
11
|
/** Abort all requests issued by this client. */
|
|
8
12
|
signal?: AbortSignal;
|
|
@@ -54,4 +58,3 @@ export declare function resolveWreqProfile(selection: StealthProfileSelection, w
|
|
|
54
58
|
};
|
|
55
59
|
export declare function normalizeResponse(response: StealthTransportResponse, requestUrl?: string, maxBodyBytes?: number): Promise<StealthResponse>;
|
|
56
60
|
export declare function createStealthClient(baseUrl: string, clientOptions?: StealthClientOptions): StealthClient;
|
|
57
|
-
export {};
|
package/dist/runtime/stealth.js
CHANGED
|
@@ -4,6 +4,8 @@ import { DEFAULT_SMARTPROXY_POOL_SIZE, invalidateProxyResolutionCacheAsync, Prox
|
|
|
4
4
|
import { SDKError, TransportError } from "../errors.js";
|
|
5
5
|
import { DEFAULT_STEALTH_BROWSER, DEFAULT_STEALTH_OS, getStealthProfile, resolverClientProfileFamily, resolveStealthProfileSelection, } from "../stealth/profiles.js";
|
|
6
6
|
import { chrome149HeaderOrder } from "./chrome149-header-order.js";
|
|
7
|
+
import { registerDiagnosticValue } from "./diagnostic-env.js";
|
|
8
|
+
import { isStealthOwnedHeaderName } from "./stealth-owned-headers.js";
|
|
7
9
|
import { ENGINE_CEREMONY_EGRESS_LEASE, } from "./egress-lease.js";
|
|
8
10
|
import { createProxyAuthIpDeniedError, createProxyEdgeAuthRejectedError, createProxyEdgeTlsRejectedError, createProxyPoolExhaustedError, createProxyPoolStaleError, isProxyAuthIpDeniedMessage, isProxyEdgeAuthRejectedMessage, isProxyEdgeTlsRejectedResponse, isProxyPoolRefreshableError, isProxyPoolStaleMessage, isProxyPoolStaleStatus, PROXY_EDGE_AUTH_REJECTED_CODE, PROXY_POOL_STALE_CODE, } from "./proxy-errors.js";
|
|
9
11
|
import { computeProxyAttemptIndex, computeProxyTransportRetryDelayMs, createDefaultProxyTransportRetryOptions, isProxyTransportRetryMethod, normalizeProxyTransportRetryOptions, shouldRetryProxyTransportAttempt, validateUnsafeProxyTransportRetryMethods, } from "./proxy-retry-policy.js";
|
|
@@ -171,15 +173,6 @@ function normalizedHeaderEntries(headers) {
|
|
|
171
173
|
}
|
|
172
174
|
return entries;
|
|
173
175
|
}
|
|
174
|
-
const SDK_OWNED_EXACT_CHROME_HEADERS = new Set([
|
|
175
|
-
"host",
|
|
176
|
-
"connection",
|
|
177
|
-
"user-agent",
|
|
178
|
-
"sec-ch-ua",
|
|
179
|
-
"sec-ch-ua-mobile",
|
|
180
|
-
"sec-ch-ua-platform",
|
|
181
|
-
"accept-encoding",
|
|
182
|
-
]);
|
|
183
176
|
// Non-pseudo-header order of real Chrome 149. The fixture captures
|
|
184
177
|
// (chrome-ground-truth-capture.json, chrome-extended-capture.json,
|
|
185
178
|
// h1-casing-capture.json) were taken through Playwright's `locale` option, which
|
|
@@ -344,7 +337,7 @@ function normalizedCallerHeaderEntriesFromRecord(headers) {
|
|
|
344
337
|
}
|
|
345
338
|
function assertCallerHeadersSupported(entries) {
|
|
346
339
|
for (const [name] of entries) {
|
|
347
|
-
if (
|
|
340
|
+
if (isStealthOwnedHeaderName(name)) {
|
|
348
341
|
throw new SDKError(`Stealth transport owns the "${name}" header; remove it from headers.`, {
|
|
349
342
|
code: "STEALTH_HEADER_OVERRIDE_UNSUPPORTED",
|
|
350
343
|
});
|
|
@@ -895,7 +888,99 @@ function discardStealthRedirectBody(response) {
|
|
|
895
888
|
// failure must not replace or delay that decision.
|
|
896
889
|
}
|
|
897
890
|
}
|
|
898
|
-
|
|
891
|
+
/** Telemetry must never replace a transport result, including with caller-provided sinks. */
|
|
892
|
+
function emitStealthTelemetry(sink, record) {
|
|
893
|
+
if (!sink)
|
|
894
|
+
return;
|
|
895
|
+
try {
|
|
896
|
+
record(sink);
|
|
897
|
+
}
|
|
898
|
+
catch {
|
|
899
|
+
/* The request owns its result. */
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
function stripStealthCookieMaterial(text, cookieNames) {
|
|
903
|
+
// Header-shaped Cookie/Set-Cookie material is redacted wholesale, including
|
|
904
|
+
// foreign names. Bare pairs outside a header are limited to jar-known names:
|
|
905
|
+
// a foreign bare name is indistinguishable from benign key=value prose and is
|
|
906
|
+
// therefore covered only when layer 1 registered its value.
|
|
907
|
+
let result = text.replace(/(^|[^\p{L}\p{N}_-])[\t ]*(?:cookie|set-cookie)[\t ]*(?::|=)[^\r\n]*/giu, "$1[REDACTED]");
|
|
908
|
+
result = result.replace(/"(?:cookie|set-cookie)"[\t ]*:[\t ]*"(?:\\.|[^"\\])*"/giu, "[REDACTED]");
|
|
909
|
+
for (const name of cookieNames) {
|
|
910
|
+
const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
911
|
+
result = result.replace(new RegExp(`(^|[;,&?\\s])${escaped}\\s*=\\s*[^;,\\s&\\r\\n]+`, "giu"), "$1[REDACTED]");
|
|
912
|
+
}
|
|
913
|
+
return result;
|
|
914
|
+
}
|
|
915
|
+
function startStealthExchange(telemetry, method, options, signal) {
|
|
916
|
+
if (!telemetry)
|
|
917
|
+
return () => { };
|
|
918
|
+
const startedAt = Date.now();
|
|
919
|
+
const requestClass = chromeRequestClass(method, options.stealth?.requestClass);
|
|
920
|
+
let recorded = false;
|
|
921
|
+
return (status, error) => {
|
|
922
|
+
if (recorded)
|
|
923
|
+
return;
|
|
924
|
+
recorded = true;
|
|
925
|
+
emitStealthTelemetry(telemetry?.sink, (sink) => {
|
|
926
|
+
let code;
|
|
927
|
+
if (error !== undefined) {
|
|
928
|
+
try {
|
|
929
|
+
code = signal?.aborted
|
|
930
|
+
? "transport_cancelled"
|
|
931
|
+
: normalizeStealthTransportError(error).code;
|
|
932
|
+
}
|
|
933
|
+
catch {
|
|
934
|
+
code = "other";
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
const knownCodes = [
|
|
938
|
+
"transport_network_error",
|
|
939
|
+
"transport_timeout",
|
|
940
|
+
"transport_cancelled",
|
|
941
|
+
"upstream_http_error",
|
|
942
|
+
"response_too_large",
|
|
943
|
+
"proxy_connect_failed",
|
|
944
|
+
"PROXY_POOL_STALE",
|
|
945
|
+
"PROXY_EDGE_AUTH_REJECTED",
|
|
946
|
+
"PROXY_AUTH_IP_DENIED",
|
|
947
|
+
"PROXY_EDGE_TLS_REJECTED",
|
|
948
|
+
"PROXY_REQUIRED",
|
|
949
|
+
];
|
|
950
|
+
const errorCode = code
|
|
951
|
+
? knownCodes.includes(code)
|
|
952
|
+
? code
|
|
953
|
+
: "other"
|
|
954
|
+
: status !== undefined && status >= 400
|
|
955
|
+
? "upstream_http_error"
|
|
956
|
+
: undefined;
|
|
957
|
+
const strip = (text) => stripStealthCookieMaterial(text, telemetry.cookieJar?.names() ?? []);
|
|
958
|
+
sink.recordAttempt({
|
|
959
|
+
ms: Date.now() - startedAt,
|
|
960
|
+
profileId: telemetry.profileId,
|
|
961
|
+
proxyUsed: telemetry.proxyUsed,
|
|
962
|
+
kind: telemetry.kind,
|
|
963
|
+
requestClass: requestClass === "navigation" && options.stealth?.userActivation === false
|
|
964
|
+
? "script_navigation"
|
|
965
|
+
: requestClass,
|
|
966
|
+
...(status === undefined ? {} : { status }),
|
|
967
|
+
...(errorCode ? { errorCode } : {}),
|
|
968
|
+
...(error === undefined
|
|
969
|
+
? {}
|
|
970
|
+
: {
|
|
971
|
+
diagnostics: {
|
|
972
|
+
name: strip(error instanceof Error ? error.name : "Error"),
|
|
973
|
+
message: strip(error instanceof Error ? error.message : String(error)),
|
|
974
|
+
...(error instanceof Error && "code" in error && typeof error.code === "string"
|
|
975
|
+
? { code: strip(error.code) }
|
|
976
|
+
: {}),
|
|
977
|
+
},
|
|
978
|
+
}),
|
|
979
|
+
});
|
|
980
|
+
});
|
|
981
|
+
};
|
|
982
|
+
}
|
|
983
|
+
async function fetchStealthRedirectChain(transport, cookieJar, requestUrl, method, options, signal, buildHeaders, telemetry) {
|
|
899
984
|
let currentUrl = requestUrl;
|
|
900
985
|
let currentMethod = method;
|
|
901
986
|
let currentBody = options.body === undefined ? undefined : normalizeBody(options.body);
|
|
@@ -903,80 +988,98 @@ async function fetchStealthRedirectChain(transport, cookieJar, requestUrl, metho
|
|
|
903
988
|
let followedHops = 0;
|
|
904
989
|
let response;
|
|
905
990
|
const deadline = options.timeout ? performance.now() + options.timeout : undefined;
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
991
|
+
let finishExchange;
|
|
992
|
+
let status;
|
|
993
|
+
let exchangeError;
|
|
994
|
+
try {
|
|
995
|
+
while (true) {
|
|
996
|
+
throwIfAmbientAborted(signal);
|
|
997
|
+
const headers = { ...currentHeaders };
|
|
998
|
+
if (!hasHeader(headers, "cookie")) {
|
|
999
|
+
const cookieHeader = cookieJar.toHeader(currentUrl);
|
|
1000
|
+
if (cookieHeader)
|
|
1001
|
+
headers.cookie = cookieHeader;
|
|
1002
|
+
}
|
|
1003
|
+
const requestInit = {
|
|
1004
|
+
headers: buildHeaders
|
|
1005
|
+
? buildHeaders(currentUrl, currentMethod, currentBody, headers)
|
|
1006
|
+
: headers,
|
|
1007
|
+
method: currentMethod,
|
|
1008
|
+
redirect: "manual",
|
|
1009
|
+
...(new URL(currentUrl).protocol === "http:" ? { disableDefaultHeaders: true } : {}),
|
|
1010
|
+
...(signal ? { signal } : {}),
|
|
1011
|
+
};
|
|
1012
|
+
if (currentBody !== undefined)
|
|
1013
|
+
requestInit.body = currentBody;
|
|
1014
|
+
await transport.clearCookies();
|
|
1015
|
+
throwIfAmbientAborted(signal);
|
|
1016
|
+
const remainingTimeout = deadline === undefined ? undefined : Math.ceil(deadline - performance.now());
|
|
1017
|
+
if (remainingTimeout !== undefined && remainingTimeout <= 0) {
|
|
1018
|
+
throw new TransportError("Request timed out", {
|
|
1019
|
+
code: "transport_timeout",
|
|
1020
|
+
status: 0,
|
|
1021
|
+
});
|
|
1022
|
+
}
|
|
1023
|
+
if (remainingTimeout !== undefined)
|
|
1024
|
+
requestInit.timeout = remainingTimeout;
|
|
1025
|
+
status = undefined;
|
|
1026
|
+
finishExchange = startStealthExchange(telemetry, currentMethod, options, signal);
|
|
1027
|
+
response = await transport.fetch(currentUrl, requestInit);
|
|
1028
|
+
status = response.status;
|
|
1029
|
+
if (signal?.aborted) {
|
|
1030
|
+
discardStealthRedirectBody(response);
|
|
1031
|
+
throw toAmbientCancellationError(signal);
|
|
1032
|
+
}
|
|
1033
|
+
cookieJar.setFromCookieStrings(setCookieHeadersFromResponse(response.headers), response.url ?? currentUrl);
|
|
1034
|
+
if (!isRedirectStatus(response.status) || options.redirect === "manual")
|
|
1035
|
+
break;
|
|
1036
|
+
if (options.redirect === "error") {
|
|
1037
|
+
discardStealthRedirectBody(response);
|
|
1038
|
+
throw new TransportError("Stealth request encountered a redirect", {
|
|
1039
|
+
code: "transport_network_error",
|
|
1040
|
+
status: 0,
|
|
1041
|
+
});
|
|
1042
|
+
}
|
|
1043
|
+
const nextUrl = resolveRedirectUrl(response.headers.get("location") ?? undefined, response.url ?? currentUrl);
|
|
1044
|
+
if (!nextUrl)
|
|
1045
|
+
break;
|
|
1046
|
+
if (followedHops >= MAX_STEALTH_REDIRECT_HOPS) {
|
|
1047
|
+
discardStealthRedirectBody(response);
|
|
1048
|
+
throw new TransportError(`Stealth request exceeded the ${MAX_STEALTH_REDIRECT_HOPS}-redirect limit`, { code: "transport_network_error", status: 0 });
|
|
1049
|
+
}
|
|
1050
|
+
assertStealthRedirectUrl(nextUrl);
|
|
955
1051
|
discardStealthRedirectBody(response);
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
1052
|
+
const nextMethod = nextRedirectMethod(response.status, currentMethod);
|
|
1053
|
+
if (nextMethod !== currentMethod) {
|
|
1054
|
+
currentBody = undefined;
|
|
1055
|
+
currentHeaders = withoutRedirectBodyHeaders(currentHeaders);
|
|
1056
|
+
}
|
|
1057
|
+
currentMethod = nextMethod;
|
|
1058
|
+
currentUrl = nextUrl;
|
|
1059
|
+
followedHops += 1;
|
|
1060
|
+
emitStealthTelemetry(telemetry?.sink, (sink) => sink.recordRedirectHop());
|
|
1061
|
+
finishExchange(status);
|
|
1062
|
+
finishExchange = undefined;
|
|
964
1063
|
}
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
1064
|
+
const normalized = await normalizeResponseWithSignal(response, currentUrl, options.maxBodyBytes, signal);
|
|
1065
|
+
if (followedHops > 0)
|
|
1066
|
+
normalized.redirected = true;
|
|
1067
|
+
return { normalized, response };
|
|
1068
|
+
}
|
|
1069
|
+
catch (error) {
|
|
1070
|
+
exchangeError = error;
|
|
1071
|
+
throw error;
|
|
1072
|
+
}
|
|
1073
|
+
finally {
|
|
1074
|
+
finishExchange?.(status, exchangeError);
|
|
968
1075
|
}
|
|
969
|
-
const normalized = await normalizeResponseWithSignal(response, currentUrl, options.maxBodyBytes, signal);
|
|
970
|
-
if (followedHops > 0)
|
|
971
|
-
normalized.redirected = true;
|
|
972
|
-
return { normalized, response };
|
|
973
1076
|
}
|
|
974
1077
|
function createSessionFetcher(baseUrl, defaultProfile, clientOptions) {
|
|
975
1078
|
const clients = new Map();
|
|
976
1079
|
let closed = false;
|
|
977
1080
|
let hasWarnedMissingProxy = false;
|
|
978
1081
|
const warn = clientOptions.warn ?? console.warn;
|
|
979
|
-
const cookieJar = new StealthCookieJar([], baseUrl);
|
|
1082
|
+
const cookieJar = new StealthCookieJar([], baseUrl, registerDiagnosticValue);
|
|
980
1083
|
const akamaiSbsdState = { transactions: new Map() };
|
|
981
1084
|
const challengedReplays = new WeakMap();
|
|
982
1085
|
const ceremonyEgressLease = clientOptions[ENGINE_CEREMONY_EGRESS_LEASE];
|
|
@@ -1316,6 +1419,8 @@ function createSessionFetcher(baseUrl, defaultProfile, clientOptions) {
|
|
|
1316
1419
|
// StealthFetchOptions), any other non-2xx honours it, and the proxy attempt is
|
|
1317
1420
|
// recorded once per delivered response.
|
|
1318
1421
|
const finalizeAttempt = (attemptResponse, attemptNormalized) => {
|
|
1422
|
+
if (attemptNormalized.challenge)
|
|
1423
|
+
emitStealthTelemetry(clientOptions.stealthTelemetry, (sink) => sink.recordSbsd(attemptNormalized.challenge.outcome));
|
|
1319
1424
|
if (!attemptNormalized.challenge &&
|
|
1320
1425
|
attemptResponse.status >= 400 &&
|
|
1321
1426
|
options.throwOnHttpError !== false) {
|
|
@@ -1406,7 +1511,15 @@ function createSessionFetcher(baseUrl, defaultProfile, clientOptions) {
|
|
|
1406
1511
|
initialHeaders.cookie = cookieHeader;
|
|
1407
1512
|
}
|
|
1408
1513
|
const defaultHeaders = buildOrderedHeaders?.(requestUrl, method, requestBody, initialHeaders);
|
|
1409
|
-
const fetchOnBoundSession = (fetchUrl, fetchMethod, fetchOptions, fetchSignal, orderedHeaders = buildOrderedHeaders, sessionDefaultHeaders = defaultHeaders) => withClient(requestProfile, proxy, ignoreTlsErrors, (transport) => fetchStealthRedirectChain(transport, cookieJar, fetchUrl, fetchMethod, fetchOptions, fetchSignal, orderedHeaders
|
|
1514
|
+
const fetchOnBoundSession = (fetchUrl, fetchMethod, fetchOptions, fetchSignal, orderedHeaders = buildOrderedHeaders, sessionDefaultHeaders = defaultHeaders, kind = "request") => withClient(requestProfile, proxy, ignoreTlsErrors, (transport) => fetchStealthRedirectChain(transport, cookieJar, fetchUrl, fetchMethod, fetchOptions, fetchSignal, orderedHeaders, clientOptions.stealthTelemetry
|
|
1515
|
+
? {
|
|
1516
|
+
sink: clientOptions.stealthTelemetry,
|
|
1517
|
+
profileId: requestProfile,
|
|
1518
|
+
proxyUsed: Boolean(proxy),
|
|
1519
|
+
kind,
|
|
1520
|
+
cookieJar,
|
|
1521
|
+
}
|
|
1522
|
+
: undefined), fetchSignal, sessionDefaultHeaders);
|
|
1410
1523
|
const throwProxyTransportFault = (faultResponse, faultBody) => {
|
|
1411
1524
|
if (!proxy)
|
|
1412
1525
|
return;
|
|
@@ -1440,7 +1553,10 @@ function createSessionFetcher(baseUrl, defaultProfile, clientOptions) {
|
|
|
1440
1553
|
const detected = akamaiSbsd
|
|
1441
1554
|
? detectAkamaiSbsdChallenge(normalized, requestUrl, cookieJar, akamaiSbsd.allowedHosts, akamaiSbsdState)
|
|
1442
1555
|
: undefined;
|
|
1556
|
+
if (akamaiSbsd && !detected)
|
|
1557
|
+
emitStealthTelemetry(clientOptions.stealthTelemetry, (sink) => sink.recordSbsd({ detected: false }));
|
|
1443
1558
|
if (detected && akamaiSbsd) {
|
|
1559
|
+
emitStealthTelemetry(clientOptions.stealthTelemetry, (sink) => sink.recordSbsd("detected"));
|
|
1444
1560
|
if (challengeSolveAttempted || challengeRefetchAttempted) {
|
|
1445
1561
|
normalized.challenge = {
|
|
1446
1562
|
challenge: detected,
|
|
@@ -1506,7 +1622,7 @@ function createSessionFetcher(baseUrl, defaultProfile, clientOptions) {
|
|
|
1506
1622
|
...(init.maxBodyBytes === undefined
|
|
1507
1623
|
? {}
|
|
1508
1624
|
: { maxBodyBytes: init.maxBodyBytes }),
|
|
1509
|
-
}, boundSignal, resolverBuildHeaders, resolverBuildHeaders?.(transportUrl, init.method, init.body, normalizeHeaders(transportHeaders)));
|
|
1625
|
+
}, boundSignal, resolverBuildHeaders, resolverBuildHeaders?.(transportUrl, init.method, init.body, normalizeHeaders(transportHeaders)), "resolver");
|
|
1510
1626
|
return {
|
|
1511
1627
|
status: result.normalized.status,
|
|
1512
1628
|
headers: result.normalized.headers,
|
|
@@ -1562,6 +1678,7 @@ function createSessionFetcher(baseUrl, defaultProfile, clientOptions) {
|
|
|
1562
1678
|
}
|
|
1563
1679
|
const transactionResult = await transaction.result;
|
|
1564
1680
|
if (!transactionResult.solved) {
|
|
1681
|
+
emitStealthTelemetry(clientOptions.stealthTelemetry, (sink) => sink.recordSbsd("solve_failed"));
|
|
1565
1682
|
if (ownsTransaction) {
|
|
1566
1683
|
// The proxy delivered the challenged response; the resolver failed.
|
|
1567
1684
|
// Surface that failure as-is: it is not a transport fault to normalize
|
|
@@ -1596,9 +1713,12 @@ function createSessionFetcher(baseUrl, defaultProfile, clientOptions) {
|
|
|
1596
1713
|
attemptRecorded = false;
|
|
1597
1714
|
attemptStartedAt = Date.now();
|
|
1598
1715
|
}
|
|
1716
|
+
if (!explicitReplay)
|
|
1717
|
+
emitStealthTelemetry(clientOptions.stealthTelemetry, (sink) => sink.recordSafeRefetch());
|
|
1599
1718
|
const replayed = await fetchOnBoundSession(requestUrl, method, replayOptions, clientOptions.signal);
|
|
1600
1719
|
throwProxyTransportFault(replayed.response, replayed.normalized.body);
|
|
1601
1720
|
const persisted = detectAkamaiSbsdChallenge(replayed.normalized, requestUrl, cookieJar, akamaiSbsd.allowedHosts, akamaiSbsdState);
|
|
1721
|
+
emitStealthTelemetry(clientOptions.stealthTelemetry, (sink) => sink.recordSbsd(persisted ? "challenge_persisted" : "refetch_clear"));
|
|
1602
1722
|
if (persisted) {
|
|
1603
1723
|
replayed.normalized.challenge = {
|
|
1604
1724
|
challenge: persisted,
|
|
@@ -1718,6 +1838,7 @@ function createSessionFetcher(baseUrl, defaultProfile, clientOptions) {
|
|
|
1718
1838
|
stalePoolError &&
|
|
1719
1839
|
refreshAttempt < MAX_POLICY_PROXY_POOL_REFRESHES) {
|
|
1720
1840
|
throwIfAmbientAborted(clientOptions.signal);
|
|
1841
|
+
emitStealthTelemetry(clientOptions.stealthTelemetry, (sink) => sink.recordPoolRefresh());
|
|
1721
1842
|
await invalidateProxyResolutionCacheAsync({
|
|
1722
1843
|
proxyPolicy: clientOptions.proxyPolicy,
|
|
1723
1844
|
upstream: clientOptions.upstream,
|
|
@@ -1924,6 +2045,7 @@ function createSessionFetcher(baseUrl, defaultProfile, clientOptions) {
|
|
|
1924
2045
|
if (decision.nextMethod !== method) {
|
|
1925
2046
|
body = undefined;
|
|
1926
2047
|
}
|
|
2048
|
+
emitStealthTelemetry(clientOptions.stealthTelemetry, (sink) => sink.recordRedirectHop());
|
|
1927
2049
|
method = decision.nextMethod;
|
|
1928
2050
|
currentUrl = decision.nextUrl;
|
|
1929
2051
|
}
|
|
@@ -1967,13 +2089,34 @@ function createSessionFetcher(baseUrl, defaultProfile, clientOptions) {
|
|
|
1967
2089
|
throwIfAmbientAborted(clientOptions.signal);
|
|
1968
2090
|
await client.clearCookies();
|
|
1969
2091
|
throwIfAmbientAborted(clientOptions.signal);
|
|
1970
|
-
const
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
2092
|
+
const finishExchange = startStealthExchange(clientOptions.stealthTelemetry
|
|
2093
|
+
? {
|
|
2094
|
+
sink: clientOptions.stealthTelemetry,
|
|
2095
|
+
profileId: profile,
|
|
2096
|
+
proxyUsed: true,
|
|
2097
|
+
kind: "proxy_diagnostic",
|
|
2098
|
+
cookieJar,
|
|
2099
|
+
}
|
|
2100
|
+
: undefined, "GET", {}, clientOptions.signal);
|
|
2101
|
+
let status;
|
|
2102
|
+
let exchangeError;
|
|
2103
|
+
try {
|
|
2104
|
+
const response = await client.fetch(PROXY_AUTH_DIAGNOSTIC_URL, {
|
|
2105
|
+
method: "GET",
|
|
2106
|
+
timeout: PROXY_AUTH_DIAGNOSTIC_TIMEOUT_MS,
|
|
2107
|
+
...(clientOptions.signal ? { signal: clientOptions.signal } : {}),
|
|
2108
|
+
});
|
|
2109
|
+
status = response.status;
|
|
2110
|
+
const normalized = await normalizeResponseWithSignal(response, undefined, undefined, clientOptions.signal);
|
|
2111
|
+
return classifyProxyAuthDiagnosticMessage(normalized.body);
|
|
2112
|
+
}
|
|
2113
|
+
catch (error) {
|
|
2114
|
+
exchangeError = error;
|
|
2115
|
+
throw error;
|
|
2116
|
+
}
|
|
2117
|
+
finally {
|
|
2118
|
+
finishExchange(status, exchangeError);
|
|
2119
|
+
}
|
|
1977
2120
|
}, clientOptions.signal);
|
|
1978
2121
|
}
|
|
1979
2122
|
catch (error) {
|