@apifuse/provider-sdk 2.2.0-beta.62 → 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 +4 -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 +187 -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/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 +7 -1
- package/dist/index.js +6 -0
- package/dist/lint.d.ts +10 -0
- package/dist/lint.js +412 -49
- package/dist/provider.d.ts +5 -5
- package/dist/provider.js +2 -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/http-telemetry-guard.d.ts +10 -0
- package/dist/runtime/http-telemetry-guard.js +62 -10
- package/dist/runtime/http.js +141 -35
- 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 +7 -0
- package/dist/server/index.js +4 -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 +51 -2
- package/dist/server/serve-implementation.js +337 -90
- 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/i18n/error-messages.ts +255 -0
- package/src/i18n/index.ts +1 -0
- package/src/i18n/keys.ts +80 -6
- package/src/index.ts +72 -0
- package/src/lint.ts +522 -50
- package/src/provider.ts +10 -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/http-telemetry-guard.ts +66 -13
- package/src/runtime/http.ts +168 -37
- 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 +53 -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 +569 -108
- 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
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { bindCapabilityRoot } from "../runtime/capability-telemetry.js";
|
|
1
2
|
import { STATUS_CODES } from "node:http";
|
|
2
3
|
import { readDiagnosticEnv, withDiagnosticEnv } from "../runtime/diagnostic-env.js";
|
|
3
4
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
@@ -9,15 +10,20 @@ import { Hono } from "hono";
|
|
|
9
10
|
import { z } from "zod";
|
|
10
11
|
import { AuthAbortError, createAuthFlowHelpers } from "../auth.js";
|
|
11
12
|
import { validateFailClosedDeclaration } from "../declaration-validation.js";
|
|
12
|
-
import {
|
|
13
|
+
import { ENGINE_OWNED_PROXY_CREDENTIAL_ENV_NAMES, isEngineOwnedEnvName, readEngineProxyCredentials, } from "../engine.js";
|
|
14
|
+
import { createEngineForMode, isUnavailableProviderEngine, resolveProviderEngineMode, } from "../runtime/engine-mode.js";
|
|
15
|
+
import { SDK_VERSION } from "./sdk-version.js";
|
|
13
16
|
import { safeProviderErrorObservability } from "../error-observability.js";
|
|
17
|
+
import { providerErrorStackFrames } from "./error-stack-frames.js";
|
|
14
18
|
import { SDK_OWNED_PROVIDER_ERROR_CODES, SDK_RUNTIME_OWNED_ERROR_CODES, SDK_STATUS_MAPPED_PROVIDER_ERROR_CODES, } from "../error-resolution.js";
|
|
15
19
|
import { AuthError, isProviderError, isSessionExpiredError, isTransportError, isValidationError, ProviderError, SDKError, } from "../errors.js";
|
|
16
20
|
import { sanitizeDiagnosticText } from "../fixture-sanitization.js";
|
|
17
21
|
import { loadProviderLocaleCatalogs, localizeAuthTurn, } from "../i18n/catalog.js";
|
|
22
|
+
import { acceptLanguageHeaderValue, DEFAULT_PROVIDER_ERROR_LOCALE, localizeProviderErrorText, PROVIDER_ERROR_LOCALES, resolveProviderErrorLocale, } from "../i18n/error-messages.js";
|
|
18
23
|
import { categoryForStatus, isRetryableCategory, PROVIDER_OBSERVABILITY_TAXONOMY_VERSION, sourceForCategory, } from "../observability.js";
|
|
19
24
|
import { createScratchpad } from "../runtime/auth-flow.js";
|
|
20
25
|
import { createProviderCache } from "../runtime/cache.js";
|
|
26
|
+
import { bindCacheTelemetry, CacheTelemetryCollector } from "../runtime/cache-telemetry.js";
|
|
21
27
|
import { createHandleContext } from "../runtime/handle.js";
|
|
22
28
|
import { createCredentialContext } from "../runtime/credential.js";
|
|
23
29
|
import { bindDiagnosticSensitiveRegistry, compileProcessDiagnosticSensitiveValues, createDiagnosticRedactor, REDACTION_FAILED, isDiagnosticRedactionSuppressed, bindCriticalDiagnosticRedactor, redactCriticalDiagnosticText, redactDiagnosticText, registerDiagnosticSensitiveValues, } from "../runtime/diagnostic-redactor.js";
|
|
@@ -30,16 +36,23 @@ import { bindHttpTelemetry, isSupportedHttpBinding, warnUnsupportedHttpBinding,
|
|
|
30
36
|
import { HttpTelemetryCollector } from "../runtime/http-telemetry.js";
|
|
31
37
|
import { wrapWithInstrumentation } from "../runtime/instrumentation.js";
|
|
32
38
|
import { createOcrClientFromEnv } from "../runtime/ocr.js";
|
|
39
|
+
import { bindOcrTelemetry, OcrTelemetryCollector } from "../runtime/ocr-telemetry.js";
|
|
33
40
|
import { getProviderBaseUrl } from "../runtime/provider.js";
|
|
34
41
|
import { PROXY_AUTH_IP_DENIED_CODE, PROXY_EDGE_AUTH_REJECTED_CODE, PROXY_POOL_EXHAUSTED_CODE, } from "../runtime/proxy-errors.js";
|
|
35
42
|
import { PROVIDER_TELEMETRY_HEADER, ProxyTelemetryCollector, } from "../runtime/proxy-telemetry.js";
|
|
36
43
|
import { closedEnum, RequestTelemetry, tenantOpaqueKeys, } from "../runtime/request-telemetry.js";
|
|
37
44
|
import { bindResolverTelemetry, createUnsupportedResolverClient, inheritResolverTelemetryBinding, } from "../runtime/resolver-shared.js";
|
|
38
45
|
import { ResolverTelemetryCollector, } from "../runtime/resolver-telemetry.js";
|
|
46
|
+
import { createResolverRuntimeOptions, resolveNativeProxyPolicy, } from "../runtime/resolver-runtime-options.js";
|
|
39
47
|
import { assertRequiredSecretsPresent, listMissingRequiredSecrets, MISSING_SECRET_CODE, } from "../runtime/secrets.js";
|
|
40
48
|
import { createProviderRuntimeStateFromEnv, createUnsupportedProviderRuntimeState, } from "../runtime/state.js";
|
|
49
|
+
import { StateTelemetryCollector, instrumentProviderRuntimeState, } from "../runtime/state-telemetry.js";
|
|
41
50
|
import { StealthCookieJar } from "../runtime/stealth-cookies.js";
|
|
51
|
+
import { StealthTelemetryCollector } from "../runtime/stealth-telemetry.js";
|
|
52
|
+
import { BrowserTelemetryCollector } from "../runtime/browser-telemetry.js";
|
|
53
|
+
import { bindBrowserTelemetry, isSupportedBrowserBinding, warnUnsupportedBrowserBinding, } from "../runtime/browser-telemetry-binding.js";
|
|
42
54
|
import { createSttClientFromEnv } from "../runtime/stt.js";
|
|
55
|
+
import { bindSttTelemetry, SttTelemetryCollector } from "../runtime/stt-telemetry.js";
|
|
43
56
|
import { createTraceContext, getTraceRecorder, updateTraceContextExportMetadata, } from "../runtime/trace.js";
|
|
44
57
|
import { resolveTraceConfigFromEnv } from "../runtime/trace-config.js";
|
|
45
58
|
import { parseSchema } from "../schema.js";
|
|
@@ -83,7 +96,6 @@ function providerErrorCode(error) {
|
|
|
83
96
|
return undefined;
|
|
84
97
|
}
|
|
85
98
|
}
|
|
86
|
-
const AUTH_FLOW_LOCALES = ["en", "ko", "ja"];
|
|
87
99
|
const retryResponseMeta = new WeakMap();
|
|
88
100
|
const STATEFUL_INTERNAL_OPERATIONS_ROUTE = "/__apifuse/stateful/operations";
|
|
89
101
|
const STATEFUL_FORWARDING_SOURCE_POD_HEADER = "x-apifuse-stateful-source-pod";
|
|
@@ -113,6 +125,18 @@ export const ProviderServerStatefulForwardEnvelopeSchema = z
|
|
|
113
125
|
}).strict(),
|
|
114
126
|
})
|
|
115
127
|
.strict();
|
|
128
|
+
// Inbound compatibility boundary for rolling deploys, mirroring the outbound
|
|
129
|
+
// one in stateful-provider-owner-forwarder.ts: emitted envelopes stay strict
|
|
130
|
+
// (above), while a received envelope's nested operation request keeps the
|
|
131
|
+
// gateway route's tolerance and strips unknown keys. A source pod on a newer
|
|
132
|
+
// SDK carrying an additive OperationRequestSchema field (tenantId, #164) must
|
|
133
|
+
// not be rejected with STATEFUL_FORWARDING_ENVELOPE_INVALID by an owner pod
|
|
134
|
+
// that predates the field: the rejection is terminal for the operation and the
|
|
135
|
+
// two pods coexist for the whole rolling update. The envelope's own keys stay
|
|
136
|
+
// strict on both sides, because they are protocol rather than payload.
|
|
137
|
+
const ReceivedStatefulForwardEnvelopeSchema = ProviderServerStatefulForwardEnvelopeSchema.extend({
|
|
138
|
+
operationRequest: z.object(ProviderServerStatefulForwardEnvelopeSchema.shape.operationRequest.shape),
|
|
139
|
+
});
|
|
116
140
|
const require = createRequire(import.meta.url);
|
|
117
141
|
function normalizedCapabilityCause(error) {
|
|
118
142
|
if (error instanceof Error)
|
|
@@ -327,24 +351,6 @@ function getProviderStealthBaseUrl(provider) {
|
|
|
327
351
|
function getProviderStealthProfile(provider) {
|
|
328
352
|
return provider.stealth ? getStealthProfile(provider.stealth) : undefined;
|
|
329
353
|
}
|
|
330
|
-
/** One option set for ctx.resolver and the automatic SBSD solve, so both share identity scope, cache, proxy intent, and telemetry. */
|
|
331
|
-
function createResolverRuntimeOptions(provider, cache, identityScope, proxyPolicy, proxyClientOptions, stealthProfile, telemetry) {
|
|
332
|
-
return {
|
|
333
|
-
allowedHosts: provider.allowedHosts,
|
|
334
|
-
cache,
|
|
335
|
-
telemetry,
|
|
336
|
-
identityScope,
|
|
337
|
-
...(proxyPolicy
|
|
338
|
-
? {
|
|
339
|
-
proxyIntent: {
|
|
340
|
-
mode: proxyPolicy.mode,
|
|
341
|
-
...proxyClientOptions,
|
|
342
|
-
...(stealthProfile ? { userAgent: stealthProfile.userAgent } : {}),
|
|
343
|
-
},
|
|
344
|
-
}
|
|
345
|
-
: {}),
|
|
346
|
-
};
|
|
347
|
-
}
|
|
348
354
|
/** Shared predicate for the SBSD challenge runtime and the ceremony egress lease. */
|
|
349
355
|
function declaresAkamaiSbsdResolver(provider) {
|
|
350
356
|
return provider.resolver?.kinds.some((kind) => kind === "akamai_sbsd") === true;
|
|
@@ -367,12 +373,13 @@ function createStealthChallengeDetection(provider, resolverRuntime, resolverOver
|
|
|
367
373
|
? {
|
|
368
374
|
async solve(challenge, transport, solveSignal) {
|
|
369
375
|
const resolver = resolverRuntime.bindResolverSignal((resolverOverride
|
|
370
|
-
? bindResolverTelemetry(resolverOverride, resolverOptions.telemetry)
|
|
376
|
+
? bindResolverTelemetry(resolverOverride, resolverOptions.telemetry, resolverOptions.browserTelemetry)
|
|
371
377
|
: undefined) ??
|
|
372
378
|
resolverRuntime.createResolverClientFromEnv(provider.resolver, undefined, {
|
|
373
379
|
allowedHosts: resolverOptions.allowedHosts,
|
|
374
380
|
cache: resolverOptions.cache,
|
|
375
381
|
telemetry: resolverOptions.telemetry,
|
|
382
|
+
browserTelemetry: resolverOptions.browserTelemetry,
|
|
376
383
|
identityScope: resolverOptions.identityScope,
|
|
377
384
|
// No proxyIntent: the transport is already bound to the initiating
|
|
378
385
|
// request's lease, and a second identity resolution would allocate
|
|
@@ -465,19 +472,16 @@ function resolveOperationConnectionId(request) {
|
|
|
465
472
|
// absent so it can never override a valid id or key a real scope. Requests
|
|
466
473
|
// without any usable id fall back to the documented missing-connection
|
|
467
474
|
// sentinel scope instead of scoping context/affinity/state under "".
|
|
468
|
-
return (
|
|
475
|
+
return normalizeIdentifier(request.connection?.id) ?? normalizeIdentifier(request.connectionId);
|
|
469
476
|
}
|
|
470
|
-
function
|
|
471
|
-
|
|
477
|
+
function resolveOperationTenantId(request) {
|
|
478
|
+
// Only the gateway-asserted envelope field is consulted; caller headers can
|
|
479
|
+
// never populate the principal scope. Same rule as connection ids: "" is a
|
|
480
|
+
// malformed identifier, not a principal.
|
|
481
|
+
return normalizeIdentifier(request.tenantId);
|
|
472
482
|
}
|
|
473
|
-
function
|
|
474
|
-
|
|
475
|
-
return provider.proxy;
|
|
476
|
-
if (provider.proxy === true)
|
|
477
|
-
return { mode: "optional" };
|
|
478
|
-
if (provider.proxy === false)
|
|
479
|
-
return { mode: "disabled" };
|
|
480
|
-
return undefined;
|
|
483
|
+
function normalizeIdentifier(id) {
|
|
484
|
+
return id === "" ? undefined : id;
|
|
481
485
|
}
|
|
482
486
|
function providerSecretNames(provider) {
|
|
483
487
|
return (provider.secrets?.map((secret) => secret.name) ?? []).filter((name) => !isEngineOwnedEnvName(name));
|
|
@@ -495,11 +499,12 @@ function createProviderContext(provider, request, operationId, options, state =
|
|
|
495
499
|
engineCredentials: engineProxyCredentials,
|
|
496
500
|
};
|
|
497
501
|
const resolverIdentityScope = resolveProviderResolverIdentityScope(provider, proxyClientOptions.affinityKey, request.requestId);
|
|
498
|
-
const cache = createProviderCache({ providerId: provider.id });
|
|
502
|
+
const cache = createProviderCache(bindCacheTelemetry({ providerId: provider.id }, scope.cacheTelemetry));
|
|
499
503
|
const { capabilityModules } = options;
|
|
500
|
-
const resolverOptions = createResolverRuntimeOptions(provider, cache, resolverIdentityScope, proxyPolicy, proxyClientOptions, stealthProfile, scope.resolverTelemetry);
|
|
504
|
+
const resolverOptions = createResolverRuntimeOptions(provider, cache, resolverIdentityScope, proxyPolicy, proxyClientOptions, stealthProfile, scope.resolverTelemetry, scope.browserTelemetry);
|
|
501
505
|
const challengeRuntime = createStealthChallengeDetection(provider, capabilityModules.resolver, options.resolver, resolverOptions, scope.trace, signal);
|
|
502
506
|
const stealthClientOptions = {
|
|
507
|
+
stealthTelemetry: scope.stealthTelemetry,
|
|
503
508
|
upstream: proxyClientOptions.upstream,
|
|
504
509
|
affinityKey: proxyClientOptions.affinityKey,
|
|
505
510
|
telemetry: scope.telemetry.proxy,
|
|
@@ -524,11 +529,15 @@ function createProviderContext(provider, request, operationId, options, state =
|
|
|
524
529
|
scopes: request.connection?.scopes,
|
|
525
530
|
values: request.connection?.secrets,
|
|
526
531
|
});
|
|
532
|
+
const operationTenantId = resolveOperationTenantId(request);
|
|
527
533
|
const requestContext = {
|
|
528
534
|
connectionId: resolveOperationConnectionId(request),
|
|
535
|
+
// Absent stays absent: an own property with an undefined value would
|
|
536
|
+
// change the shape of ctx.request for every existing consumer.
|
|
537
|
+
...(operationTenantId !== undefined ? { tenantId: operationTenantId } : {}),
|
|
529
538
|
headers: request.headers ?? {},
|
|
530
539
|
};
|
|
531
|
-
const requestState = state.forConnection(requestContext.connectionId);
|
|
540
|
+
const requestState = instrumentProviderRuntimeState(state, scope.stateTelemetry, scope.redact).forConnection(requestContext.connectionId);
|
|
532
541
|
const bindings = {
|
|
533
542
|
env,
|
|
534
543
|
credential,
|
|
@@ -554,6 +563,7 @@ function createProviderContext(provider, request, operationId, options, state =
|
|
|
554
563
|
requireCdpPool: isProductionProviderBrowserMode(provider),
|
|
555
564
|
stealth: true,
|
|
556
565
|
engine: provider.browser?.engine,
|
|
566
|
+
telemetry: scope.browserTelemetry,
|
|
557
567
|
})
|
|
558
568
|
: createBrowserStub(),
|
|
559
569
|
...(provider.native
|
|
@@ -572,15 +582,15 @@ function createProviderContext(provider, request, operationId, options, state =
|
|
|
572
582
|
: {}),
|
|
573
583
|
trace: scope.trace,
|
|
574
584
|
auth: createAuthStub(),
|
|
575
|
-
ocr: options.ocr ?? createOcrClientFromEnv(provider.ocr),
|
|
576
|
-
stt: options.stt ?? createSttClientFromEnv(provider.stt),
|
|
585
|
+
ocr: bindCapabilityRoot(bindOcrTelemetry(options.ocr ?? createOcrClientFromEnv(provider.ocr), scope.ocrTelemetry), scope.run),
|
|
586
|
+
stt: bindCapabilityRoot(bindSttTelemetry(options.stt ?? createSttClientFromEnv(provider.stt), scope.sttTelemetry), scope.run),
|
|
577
587
|
resolver: capabilityModules.resolver
|
|
578
588
|
? capabilityModules.resolver.bindResolverSignal((options.resolver
|
|
579
|
-
? bindResolverTelemetry(options.resolver, resolverOptions.telemetry)
|
|
589
|
+
? bindResolverTelemetry(options.resolver, resolverOptions.telemetry, resolverOptions.browserTelemetry)
|
|
580
590
|
: undefined) ??
|
|
581
591
|
capabilityModules.resolver.createResolverClientFromEnv(provider.resolver, undefined, resolverOptions), signal)
|
|
582
592
|
: bindResolverSignalWithoutRuntime((options.resolver
|
|
583
|
-
? bindResolverTelemetry(options.resolver, resolverOptions.telemetry)
|
|
593
|
+
? bindResolverTelemetry(options.resolver, resolverOptions.telemetry, resolverOptions.browserTelemetry)
|
|
584
594
|
: undefined) ??
|
|
585
595
|
createUnsupportedResolverClient("Provider does not declare resolver capability"), signal),
|
|
586
596
|
handle: createHandleContext({
|
|
@@ -595,6 +605,7 @@ function createProviderContext(provider, request, operationId, options, state =
|
|
|
595
605
|
}),
|
|
596
606
|
};
|
|
597
607
|
const candidateHttp = bindings.http;
|
|
608
|
+
const candidateBrowser = bindings.browser;
|
|
598
609
|
const attached = options.engine.attach({ provider, bindings });
|
|
599
610
|
const hostHttp = provider.http ? attached.http : undefined;
|
|
600
611
|
const supportedHostHttp = provider.http && isSupportedHttpBinding(hostHttp);
|
|
@@ -603,10 +614,23 @@ function createProviderContext(provider, request, operationId, options, state =
|
|
|
603
614
|
const observedHttp = supportedHostHttp && hostHttp !== candidateHttp
|
|
604
615
|
? bindHttpTelemetry(hostHttp, scope.httpTelemetry)
|
|
605
616
|
: undefined;
|
|
606
|
-
const
|
|
617
|
+
const hostBrowser = provider.runtime === "browser" ? attached.browser : undefined;
|
|
618
|
+
const supportedHostBrowser = provider.runtime === "browser" && isSupportedBrowserBinding(hostBrowser);
|
|
619
|
+
if (provider.runtime === "browser" && !supportedHostBrowser)
|
|
620
|
+
warnUnsupportedBrowserBinding();
|
|
621
|
+
const observedBrowser = supportedHostBrowser && hostBrowser !== candidateBrowser
|
|
622
|
+
? bindBrowserTelemetry(hostBrowser, scope.browserTelemetry)
|
|
623
|
+
: undefined;
|
|
624
|
+
const contextTarget = observedBrowser || observedHttp
|
|
607
625
|
? new Proxy(attached, {
|
|
608
626
|
get(target, property, receiver) {
|
|
609
|
-
|
|
627
|
+
if (property === "http" && observedHttp)
|
|
628
|
+
return observedHttp;
|
|
629
|
+
if (property === "http" && provider.http && !supportedHostHttp)
|
|
630
|
+
return undefined;
|
|
631
|
+
if (property === "browser" && observedBrowser)
|
|
632
|
+
return observedBrowser;
|
|
633
|
+
return Reflect.get(target, property, receiver);
|
|
610
634
|
},
|
|
611
635
|
})
|
|
612
636
|
: provider.http && !supportedHostHttp
|
|
@@ -687,11 +711,12 @@ function createAuthFlowContext(provider, request, route, options, state, scope,
|
|
|
687
711
|
throw new SDKError("An egress lease was supplied for an auth flow that does not use a ceremony lease", { code: "EGRESS_LEASE_INVALID" });
|
|
688
712
|
}
|
|
689
713
|
const resolverIdentityScope = resolveProviderResolverIdentityScope(provider, proxyClientOptions.affinityKey, request.requestId);
|
|
690
|
-
const cache = createProviderCache({ providerId: provider.id });
|
|
714
|
+
const cache = createProviderCache(bindCacheTelemetry({ providerId: provider.id }, scope.cacheTelemetry));
|
|
691
715
|
const { capabilityModules } = options;
|
|
692
|
-
const resolverOptions = createResolverRuntimeOptions(provider, cache, resolverIdentityScope, proxyPolicy, proxyClientOptions, stealthProfile, scope.resolverTelemetry);
|
|
716
|
+
const resolverOptions = createResolverRuntimeOptions(provider, cache, resolverIdentityScope, proxyPolicy, proxyClientOptions, stealthProfile, scope.resolverTelemetry, scope.browserTelemetry);
|
|
693
717
|
const challengeRuntime = createStealthChallengeDetection(provider, capabilityModules.resolver, options.resolver, resolverOptions, scope.trace, signal);
|
|
694
718
|
const stealthClientOptions = {
|
|
719
|
+
stealthTelemetry: scope.stealthTelemetry,
|
|
695
720
|
upstream: proxyClientOptions.upstream,
|
|
696
721
|
affinityKey: proxyClientOptions.affinityKey,
|
|
697
722
|
telemetry: scope.telemetry.proxy,
|
|
@@ -730,12 +755,23 @@ function createAuthFlowContext(provider, request, route, options, state, scope,
|
|
|
730
755
|
...(signal ? { signal } : {}),
|
|
731
756
|
httpTelemetry: scope.httpTelemetry,
|
|
732
757
|
}),
|
|
733
|
-
state: state.forConnection(resolveOperationConnectionId(request)),
|
|
758
|
+
state: instrumentProviderRuntimeState(state, scope.stateTelemetry, scope.redact).forConnection(resolveOperationConnectionId(request)),
|
|
734
759
|
stealth: stealthBaseUrl
|
|
735
760
|
? capabilityModules.stealth
|
|
736
761
|
? capabilityModules.stealth.createStealthClient(stealthBaseUrl, stealthClientOptions)
|
|
737
762
|
: createLazyStealthClient(logStealthCleanupError, stealthBaseUrl, stealthClientOptions)
|
|
738
763
|
: createStealthStub(),
|
|
764
|
+
browser: provider.runtime === "browser"
|
|
765
|
+
? capabilityModules.browser.createBrowserClient({
|
|
766
|
+
allowedHosts: provider.allowedHosts,
|
|
767
|
+
cdpUrl: readDiagnosticEnv("APIFUSE__CDP_POOL__URL"),
|
|
768
|
+
headless: true,
|
|
769
|
+
requireCdpPool: isProductionProviderBrowserMode(provider),
|
|
770
|
+
stealth: true,
|
|
771
|
+
engine: provider.browser?.engine,
|
|
772
|
+
telemetry: scope.browserTelemetry,
|
|
773
|
+
})
|
|
774
|
+
: createBrowserStub(),
|
|
739
775
|
...(provider.native
|
|
740
776
|
? {
|
|
741
777
|
native: {
|
|
@@ -756,15 +792,15 @@ function createAuthFlowContext(provider, request, route, options, state, scope,
|
|
|
756
792
|
]),
|
|
757
793
|
credential,
|
|
758
794
|
context: flowContextStore.context,
|
|
759
|
-
ocr: options.ocr ?? createOcrClientFromEnv(provider.ocr),
|
|
760
|
-
stt: options.stt ?? createSttClientFromEnv(provider.stt),
|
|
795
|
+
ocr: bindCapabilityRoot(bindOcrTelemetry(options.ocr ?? createOcrClientFromEnv(provider.ocr), scope.ocrTelemetry), scope.run),
|
|
796
|
+
stt: bindCapabilityRoot(bindSttTelemetry(options.stt ?? createSttClientFromEnv(provider.stt), scope.sttTelemetry), scope.run),
|
|
761
797
|
resolver: capabilityModules.resolver
|
|
762
798
|
? capabilityModules.resolver.bindResolverSignal((options.resolver
|
|
763
|
-
? bindResolverTelemetry(options.resolver, resolverOptions.telemetry)
|
|
799
|
+
? bindResolverTelemetry(options.resolver, resolverOptions.telemetry, resolverOptions.browserTelemetry)
|
|
764
800
|
: undefined) ??
|
|
765
801
|
capabilityModules.resolver.createResolverClientFromEnv(provider.resolver, undefined, resolverOptions), signal)
|
|
766
802
|
: bindResolverSignalWithoutRuntime((options.resolver
|
|
767
|
-
? bindResolverTelemetry(options.resolver, resolverOptions.telemetry)
|
|
803
|
+
? bindResolverTelemetry(options.resolver, resolverOptions.telemetry, resolverOptions.browserTelemetry)
|
|
768
804
|
: undefined) ??
|
|
769
805
|
createUnsupportedResolverClient("Provider does not declare resolver capability"), signal),
|
|
770
806
|
auth: createAuthFlowHelpers({ signal }),
|
|
@@ -828,7 +864,76 @@ function publicErrorSource(error, category) {
|
|
|
828
864
|
}
|
|
829
865
|
return sourceForCategory(category);
|
|
830
866
|
}
|
|
831
|
-
function
|
|
867
|
+
function localeKeyOption(error, key) {
|
|
868
|
+
const value = providerErrorOption(error, key);
|
|
869
|
+
return typeof value === "string" ? value : undefined;
|
|
870
|
+
}
|
|
871
|
+
function declaredLocaleKey(declaration, key) {
|
|
872
|
+
const value = declaration?.[key];
|
|
873
|
+
return typeof value === "string" ? value : undefined;
|
|
874
|
+
}
|
|
875
|
+
function providerErrorParams(error) {
|
|
876
|
+
const params = providerErrorOption(error, "params");
|
|
877
|
+
return params !== null && typeof params === "object" && !Array.isArray(params)
|
|
878
|
+
? params
|
|
879
|
+
: undefined;
|
|
880
|
+
}
|
|
881
|
+
/**
|
|
882
|
+
* Resolution order for one localized envelope field:
|
|
883
|
+
*
|
|
884
|
+
* 1. the throw site's `messageKey`/`fixKey`;
|
|
885
|
+
* 2. the declared `errorCodes[]` entry's key for the thrown code;
|
|
886
|
+
* 3. the derived `errors.<code>.<field>` convention;
|
|
887
|
+
* 4. the English literal the provider threw.
|
|
888
|
+
*
|
|
889
|
+
* Steps 2 and 3 are skipped for SDK-owned failures (transport, Zod, stateful
|
|
890
|
+
* deadline, SDK runtime codes): their text is the SDK's contract, and a
|
|
891
|
+
* provider catalog entry must not be able to relabel one. An explicit key on
|
|
892
|
+
* the thrown error still wins, because that is the provider deliberately
|
|
893
|
+
* describing an error it constructed itself.
|
|
894
|
+
*/
|
|
895
|
+
function localizedErrorField(error, field, literal, localization) {
|
|
896
|
+
if (!localization?.catalogs)
|
|
897
|
+
return literal;
|
|
898
|
+
const optionKey = field === "message" ? "messageKey" : "fixKey";
|
|
899
|
+
const candidates = [
|
|
900
|
+
{ kind: "key", key: localeKeyOption(error, optionKey) },
|
|
901
|
+
];
|
|
902
|
+
if (!sdkOwnsErrorResolution(error)) {
|
|
903
|
+
candidates.push({ kind: "key", key: declaredLocaleKey(localization.declaredErrorCode, optionKey) }, { kind: "derived", code: providerErrorCode(error), field });
|
|
904
|
+
}
|
|
905
|
+
return localizeProviderErrorText({
|
|
906
|
+
catalogs: localization.catalogs,
|
|
907
|
+
locale: localization.locale,
|
|
908
|
+
candidates,
|
|
909
|
+
params: providerErrorParams(error),
|
|
910
|
+
fallback: literal,
|
|
911
|
+
});
|
|
912
|
+
}
|
|
913
|
+
/**
|
|
914
|
+
* Reads `accept-language` out of the request envelope's `headers` map.
|
|
915
|
+
*
|
|
916
|
+
* The gateway stamps the negotiated locale there for auth flows (it persists
|
|
917
|
+
* the start locale on the flow state so continue/poll turns stay in one
|
|
918
|
+
* language), and the operation route merges HTTP headers into the same map, so
|
|
919
|
+
* the envelope is the higher-precedence source.
|
|
920
|
+
*/
|
|
921
|
+
function requestBodyAcceptLanguage(rawBody) {
|
|
922
|
+
if (!rawBody || typeof rawBody !== "object")
|
|
923
|
+
return undefined;
|
|
924
|
+
const headers = Object.getOwnPropertyDescriptor(rawBody, "headers")?.value;
|
|
925
|
+
if (!headers || typeof headers !== "object" || Array.isArray(headers))
|
|
926
|
+
return undefined;
|
|
927
|
+
return acceptLanguageHeaderValue(headers);
|
|
928
|
+
}
|
|
929
|
+
function errorEnvelopeLocalization(options) {
|
|
930
|
+
return {
|
|
931
|
+
...(options.catalogs ? { catalogs: options.catalogs } : {}),
|
|
932
|
+
locale: resolveProviderErrorLocale(requestBodyAcceptLanguage(options.rawBody), options.requestHeaders?.get("accept-language")),
|
|
933
|
+
...(options.declaredErrorCode ? { declaredErrorCode: options.declaredErrorCode } : {}),
|
|
934
|
+
};
|
|
935
|
+
}
|
|
936
|
+
function toErrorResponse(error, requestId, observabilityDetails, redact, localization) {
|
|
832
937
|
const observability = observabilityDetails;
|
|
833
938
|
const source = publicErrorSource(error, observability.category);
|
|
834
939
|
if (error instanceof StatefulRoutingDeadlineError) {
|
|
@@ -844,14 +949,17 @@ function toErrorResponse(error, requestId, observabilityDetails, redact) {
|
|
|
844
949
|
}
|
|
845
950
|
if (isProviderError(error)) {
|
|
846
951
|
const details = providerErrorOption(error, "details");
|
|
952
|
+
const literalFix = providerErrorOption(error, "fix");
|
|
953
|
+
const fix = localizedErrorField(error, "fix", typeof literalFix === "string" && literalFix.length > 0 ? literalFix : undefined, localization);
|
|
954
|
+
const literalMessage = publicProviderErrorMessage(error);
|
|
847
955
|
return {
|
|
848
956
|
error: {
|
|
849
957
|
code: providerErrorCode(error) ?? "provider_error",
|
|
850
|
-
message:
|
|
958
|
+
message: localizedErrorField(error, "message", literalMessage, localization) ?? literalMessage,
|
|
851
959
|
...(requestId ? { requestId } : {}),
|
|
852
960
|
retryable: observability.retryable,
|
|
853
961
|
source,
|
|
854
|
-
...(
|
|
962
|
+
...(fix ? { fix } : {}),
|
|
855
963
|
...(details !== undefined ? { details } : {}),
|
|
856
964
|
},
|
|
857
965
|
};
|
|
@@ -1097,6 +1205,11 @@ function publicProviderErrorMessage(error) {
|
|
|
1097
1205
|
return "Request timed out";
|
|
1098
1206
|
if (providerErrorCode(error) === "transport_network_error")
|
|
1099
1207
|
return "Network error";
|
|
1208
|
+
// Provider-local fault: no request was issued, so an upstream-flavored
|
|
1209
|
+
// message would misattribute it (category is provider_error).
|
|
1210
|
+
if (providerErrorCode(error) === "http_header_factory_failed") {
|
|
1211
|
+
return "Request header preparation failed";
|
|
1212
|
+
}
|
|
1100
1213
|
if (providerErrorCode(error) === "upstream_http_error" && error.status) {
|
|
1101
1214
|
return `Upstream request failed with status ${error.status}`;
|
|
1102
1215
|
}
|
|
@@ -1220,6 +1333,11 @@ function logProviderError(logger, provider, kind, route, requestId, error, statu
|
|
|
1220
1333
|
const errorClass = error instanceof Error ? error.name : typeof error;
|
|
1221
1334
|
const message = error instanceof Error ? error.message : String(error);
|
|
1222
1335
|
const causeChain = providerErrorCauseChain(error, redact);
|
|
1336
|
+
// Masked 500 bodies carry only errorClass, so the log is the sole channel
|
|
1337
|
+
// that can locate the throw. Declared 5xx (502/504) are included too: their
|
|
1338
|
+
// body carries code+message, but frame[0] is still the throw site inside
|
|
1339
|
+
// provider code. 4xx failures keep the lean record.
|
|
1340
|
+
const stack = status >= 500 ? providerErrorStackFrames(error, redact) : undefined;
|
|
1223
1341
|
const details = observabilityDetails;
|
|
1224
1342
|
const isUnregisteredProviderErrorCode = status === 500 &&
|
|
1225
1343
|
isProviderError(error) &&
|
|
@@ -1261,6 +1379,7 @@ function logProviderError(logger, provider, kind, route, requestId, error, statu
|
|
|
1261
1379
|
errorClass: redactDiagnosticText(errorClass, redact),
|
|
1262
1380
|
message: sanitizeDiagnosticText(redactDiagnosticText(message, redact)),
|
|
1263
1381
|
...(causeChain ? { causeChain } : {}),
|
|
1382
|
+
...(stack ? { stack } : {}),
|
|
1264
1383
|
...(providerObservability ? { providerObservability } : {}),
|
|
1265
1384
|
...(details.upstreamStatus ? { upstreamStatus: details.upstreamStatus } : {}),
|
|
1266
1385
|
errorCategory: details.category,
|
|
@@ -1462,6 +1581,7 @@ function createRequestScope(input) {
|
|
|
1462
1581
|
observe: createDiagnosticEnvObserver(input.provider, sensitiveRegistry.add, sensitiveRegistry.has),
|
|
1463
1582
|
finished: false,
|
|
1464
1583
|
staticValues: input.staticSensitiveValues,
|
|
1584
|
+
register: sensitiveRegistry.add,
|
|
1465
1585
|
};
|
|
1466
1586
|
const traceConfig = withDiagnosticEnv(observeEnv, () => resolveTraceConfigFromEnv());
|
|
1467
1587
|
const details = {
|
|
@@ -1492,11 +1612,23 @@ function createRequestScope(input) {
|
|
|
1492
1612
|
const resolverCollector = new ResolverTelemetryCollector({ redact });
|
|
1493
1613
|
const nativeCollector = new NativeTelemetryCollector({ redact });
|
|
1494
1614
|
const httpCollector = new HttpTelemetryCollector({ redact });
|
|
1615
|
+
const stealthCollector = new StealthTelemetryCollector({ redact });
|
|
1616
|
+
const ocrCollector = new OcrTelemetryCollector({ redact });
|
|
1617
|
+
const sttCollector = new SttTelemetryCollector({ redact });
|
|
1618
|
+
const browserCollector = new BrowserTelemetryCollector({ redact });
|
|
1619
|
+
const cacheTelemetry = new CacheTelemetryCollector({ redact });
|
|
1620
|
+
const stateTelemetry = new StateTelemetryCollector({ redact });
|
|
1495
1621
|
const telemetry = new RequestTelemetry(trace);
|
|
1496
1622
|
telemetry.register(proxyCollector);
|
|
1497
1623
|
telemetry.register(resolverCollector);
|
|
1498
1624
|
telemetry.register(nativeCollector);
|
|
1499
1625
|
telemetry.register(httpCollector);
|
|
1626
|
+
telemetry.register(stealthCollector);
|
|
1627
|
+
telemetry.register(browserCollector);
|
|
1628
|
+
telemetry.register(ocrCollector);
|
|
1629
|
+
telemetry.register(sttCollector);
|
|
1630
|
+
telemetry.register(cacheTelemetry);
|
|
1631
|
+
telemetry.register(stateTelemetry);
|
|
1500
1632
|
let rootRunner = (fn) => fn();
|
|
1501
1633
|
let resolveRoot;
|
|
1502
1634
|
const rootTerminal = new Promise((resolve) => {
|
|
@@ -1575,6 +1707,12 @@ function createRequestScope(input) {
|
|
|
1575
1707
|
resolverTelemetry: resolverCollector,
|
|
1576
1708
|
nativeTelemetry: nativeCollector,
|
|
1577
1709
|
httpTelemetry: httpCollector,
|
|
1710
|
+
stealthTelemetry: stealthCollector,
|
|
1711
|
+
ocrTelemetry: ocrCollector,
|
|
1712
|
+
sttTelemetry: sttCollector,
|
|
1713
|
+
browserTelemetry: browserCollector,
|
|
1714
|
+
cacheTelemetry,
|
|
1715
|
+
stateTelemetry,
|
|
1578
1716
|
seedCredentials(rawBody, kind) {
|
|
1579
1717
|
const harvested = rawRequestCredentials(rawBody, kind);
|
|
1580
1718
|
sensitiveRegistry.add(harvested.values);
|
|
@@ -2015,50 +2153,49 @@ function toAuthFlowResponse(result, contextPatch, engine) {
|
|
|
2015
2153
|
...(engine ? { engine } : {}),
|
|
2016
2154
|
};
|
|
2017
2155
|
}
|
|
2018
|
-
function authFlowLocaleFromHeaders(headers) {
|
|
2019
|
-
const header = Object.entries(headers ?? {}).find(([key]) => key.toLowerCase() === "accept-language")?.[1];
|
|
2020
|
-
for (const token of (header ?? "").split(",")) {
|
|
2021
|
-
const language = token.trim().split(";")[0]?.split("-")[0]?.toLowerCase();
|
|
2022
|
-
if (isAuthFlowLocale(language)) {
|
|
2023
|
-
return language;
|
|
2024
|
-
}
|
|
2025
|
-
}
|
|
2026
|
-
return "en";
|
|
2027
|
-
}
|
|
2028
|
-
function isAuthFlowLocale(value) {
|
|
2029
|
-
return value === "en" || value === "ko" || value === "ja";
|
|
2030
|
-
}
|
|
2031
2156
|
function isAuthTurn(value) {
|
|
2032
2157
|
return !!value && typeof value === "object" && "kind" in value && "turnId" in value;
|
|
2033
2158
|
}
|
|
2034
|
-
|
|
2159
|
+
/**
|
|
2160
|
+
* Loads the provider's locale catalogs once, at `createServerApp` time.
|
|
2161
|
+
*
|
|
2162
|
+
* Only the locales that actually exist on disk are read: a provider with
|
|
2163
|
+
* `en`+`ko` but no `ja.json` used to make the whole load throw and silently
|
|
2164
|
+
* disable localization for every turn. Absence of catalogs is not an error —
|
|
2165
|
+
* every localized field falls back to its English literal — but a catalog that
|
|
2166
|
+
* exists and cannot be read is logged once so a packaging mistake is visible at
|
|
2167
|
+
* boot instead of per request.
|
|
2168
|
+
*/
|
|
2169
|
+
function resolveProviderLocaleCatalogs(provider, options, logger) {
|
|
2170
|
+
if (options.localeCatalogs)
|
|
2171
|
+
return options.localeCatalogs;
|
|
2035
2172
|
for (const providerDir of [
|
|
2036
2173
|
process.cwd(),
|
|
2037
2174
|
join(process.cwd(), "providers", provider.id),
|
|
2038
2175
|
join(process.cwd(), "providers-staging", provider.id),
|
|
2039
2176
|
]) {
|
|
2040
|
-
|
|
2177
|
+
const locales = PROVIDER_ERROR_LOCALES.filter((locale) => existsSync(join(providerDir, "locales", `${locale}.json`)));
|
|
2178
|
+
if (!locales.includes(DEFAULT_PROVIDER_ERROR_LOCALE))
|
|
2041
2179
|
continue;
|
|
2042
2180
|
try {
|
|
2043
|
-
return loadProviderLocaleCatalogs({
|
|
2044
|
-
providerDir,
|
|
2045
|
-
locales: AUTH_FLOW_LOCALES,
|
|
2046
|
-
});
|
|
2181
|
+
return loadProviderLocaleCatalogs({ providerDir, locales });
|
|
2047
2182
|
}
|
|
2048
|
-
catch {
|
|
2183
|
+
catch (error) {
|
|
2184
|
+
logger({
|
|
2185
|
+
level: "warn",
|
|
2186
|
+
event: "provider_locale_catalogs_unavailable",
|
|
2187
|
+
providerId: provider.id,
|
|
2188
|
+
reason: sanitizeDiagnosticText(error instanceof Error ? error.message : String(error)),
|
|
2189
|
+
});
|
|
2049
2190
|
return undefined;
|
|
2050
2191
|
}
|
|
2051
2192
|
}
|
|
2052
2193
|
return undefined;
|
|
2053
2194
|
}
|
|
2054
|
-
function materializeAuthFlowTurn(
|
|
2055
|
-
const catalogs = loadAuthFlowLocaleCatalogs(provider);
|
|
2195
|
+
function materializeAuthFlowTurn(turn, catalogs, locale) {
|
|
2056
2196
|
if (!catalogs)
|
|
2057
2197
|
return turn;
|
|
2058
|
-
return localizeAuthTurn(turn, {
|
|
2059
|
-
catalogs,
|
|
2060
|
-
locale: authFlowLocaleFromHeaders(request.headers),
|
|
2061
|
-
});
|
|
2198
|
+
return localizeAuthTurn(turn, { catalogs, locale });
|
|
2062
2199
|
}
|
|
2063
2200
|
function withAuthRequestHeaders(request, headers) {
|
|
2064
2201
|
return {
|
|
@@ -2137,7 +2274,15 @@ async function handleOperation(provider, request, operationId, options, state =
|
|
|
2137
2274
|
await cleanup();
|
|
2138
2275
|
}
|
|
2139
2276
|
}
|
|
2140
|
-
async function handleAuthFlow(provider, request, route, options, state, scope,
|
|
2277
|
+
async function handleAuthFlow(provider, request, route, options, state, scope,
|
|
2278
|
+
/**
|
|
2279
|
+
* Negotiated once per request by the route so a successful turn and an error
|
|
2280
|
+
* envelope from the same request can never disagree. `withAuthRequestHeaders`
|
|
2281
|
+
* lets the HTTP header shadow the envelope's `Accept-Language`, but the
|
|
2282
|
+
* gateway stamps the flow's start locale into the envelope precisely so
|
|
2283
|
+
* continue/poll turns stay in one language, so the envelope wins here.
|
|
2284
|
+
*/
|
|
2285
|
+
locale, signal) {
|
|
2141
2286
|
const flow = provider.auth?.flow;
|
|
2142
2287
|
if (!flow) {
|
|
2143
2288
|
throw new ProviderError("Auth flow is not configured", {
|
|
@@ -2179,7 +2324,7 @@ async function handleAuthFlow(provider, request, route, options, state, scope, s
|
|
|
2179
2324
|
!(result instanceof Response) &&
|
|
2180
2325
|
!(result instanceof ReadableStream) &&
|
|
2181
2326
|
isAuthTurn(result)
|
|
2182
|
-
? materializeAuthFlowTurn(
|
|
2327
|
+
? materializeAuthFlowTurn(result, options.localeCatalogs, locale)
|
|
2183
2328
|
: result;
|
|
2184
2329
|
return toAuthFlowResponse(materializedResult, getPatch(), getEngineState());
|
|
2185
2330
|
}
|
|
@@ -2301,7 +2446,7 @@ function operationRequestFromForwardingEnvelope(envelope) {
|
|
|
2301
2446
|
};
|
|
2302
2447
|
}
|
|
2303
2448
|
function parseStatefulForwardingEnvelope(rawBody, redact) {
|
|
2304
|
-
const parsed =
|
|
2449
|
+
const parsed = ReceivedStatefulForwardEnvelopeSchema.safeParse(rawBody);
|
|
2305
2450
|
if (parsed.success)
|
|
2306
2451
|
return parsed.data;
|
|
2307
2452
|
throw new ProviderError("Stateful forwarding envelope is invalid.", {
|
|
@@ -2333,12 +2478,59 @@ export function createServerApp(provider, options = {}) {
|
|
|
2333
2478
|
validateStatefulServerConfig(runtimeOptions);
|
|
2334
2479
|
return createServerAppWithCapabilityModules(runtimeProvider, runtimeOptions, loadProviderCapabilityModulesSync(runtimeProvider));
|
|
2335
2480
|
}
|
|
2481
|
+
/**
|
|
2482
|
+
* Resolve the engine once at boot, before any route exists. An explicit engine
|
|
2483
|
+
* object is used as given; otherwise the resolved mode selects the engine.
|
|
2484
|
+
*
|
|
2485
|
+
* Deliberately never throws for deployment-authored input: a mode this release
|
|
2486
|
+
* cannot serve yields an engine that fails every request and a `/readyz` 503,
|
|
2487
|
+
* because a boot crash would trade a structured signal for CrashLoopBackOff
|
|
2488
|
+
* across the fleet (same trade-off as `provider_secrets_missing` above).
|
|
2489
|
+
*/
|
|
2490
|
+
function resolveServerEngine(serverOptions) {
|
|
2491
|
+
const resolution = resolveProviderEngineMode({
|
|
2492
|
+
option: serverOptions.engineMode,
|
|
2493
|
+
engine: serverOptions.engine,
|
|
2494
|
+
});
|
|
2495
|
+
if (serverOptions.engine !== undefined)
|
|
2496
|
+
return { engine: serverOptions.engine, resolution };
|
|
2497
|
+
return { engine: createEngineForMode(resolution.mode), resolution };
|
|
2498
|
+
}
|
|
2499
|
+
/**
|
|
2500
|
+
* `engine_env_ignored` is expected for the whole migration window: the manifest
|
|
2501
|
+
* generator projects the remote engine env fleet-wide before any mode flips, so
|
|
2502
|
+
* escalating on it would turn every healthy boot into a warn line. The
|
|
2503
|
+
* disagreement warnings still escalate.
|
|
2504
|
+
*/
|
|
2505
|
+
const ENGINE_MODE_INFO_WARNINGS = new Set(["engine_env_ignored"]);
|
|
2506
|
+
function engineModeLogEvent(provider, resolution, attached) {
|
|
2507
|
+
const escalating = resolution.warnings.filter((warning) => !ENGINE_MODE_INFO_WARNINGS.has(warning));
|
|
2508
|
+
return {
|
|
2509
|
+
level: attached && escalating.length === 0 ? "info" : "warn",
|
|
2510
|
+
event: "provider_engine_mode",
|
|
2511
|
+
providerId: provider.id,
|
|
2512
|
+
mode: resolution.mode,
|
|
2513
|
+
source: resolution.source,
|
|
2514
|
+
deprecated: resolution.deprecated,
|
|
2515
|
+
attached,
|
|
2516
|
+
sdkVersion: SDK_VERSION,
|
|
2517
|
+
...(provider.runtimeTarget === undefined ? {} : { runtimeTarget: provider.runtimeTarget }),
|
|
2518
|
+
...(resolution.warnings.length === 0 ? {} : { warnings: resolution.warnings }),
|
|
2519
|
+
};
|
|
2520
|
+
}
|
|
2336
2521
|
function createServerAppWithCapabilityModules(provider, serverOptions, capabilityModules) {
|
|
2522
|
+
const engineSelection = resolveServerEngine(serverOptions);
|
|
2523
|
+
// Read the provider's locale catalogs once here rather than per turn: the
|
|
2524
|
+
// previous auth-flow loader re-read all three JSON files on every turn and
|
|
2525
|
+
// threw the whole map away when one locale file was absent.
|
|
2526
|
+
const localeCatalogs = resolveProviderLocaleCatalogs(provider, serverOptions, serverOptions.logger ?? defaultProviderServerLogger);
|
|
2337
2527
|
const options = {
|
|
2338
2528
|
...serverOptions,
|
|
2529
|
+
...(localeCatalogs ? { localeCatalogs } : {}),
|
|
2339
2530
|
capabilityModules,
|
|
2340
|
-
engine:
|
|
2531
|
+
engine: engineSelection.engine,
|
|
2341
2532
|
};
|
|
2533
|
+
const engineAttached = !isUnavailableProviderEngine(options.engine);
|
|
2342
2534
|
const app = new Hono();
|
|
2343
2535
|
// Compile the startup inventory once, composed with the shared outside-context fallback.
|
|
2344
2536
|
const staticSensitiveValues = compileProcessDiagnosticSensitiveValues(collectStaticDiagnosticSensitiveValues(provider, {
|
|
@@ -2370,13 +2562,33 @@ function createServerAppWithCapabilityModules(provider, serverOptions, capabilit
|
|
|
2370
2562
|
app.notFound((c) => {
|
|
2371
2563
|
const error = new ProviderError("Not found", { code: "not_found", retryable: false });
|
|
2372
2564
|
const observabilityDetails = errorObservabilityDetails(error);
|
|
2373
|
-
return responseWithErrorObservability(c.json(toErrorResponse(error, undefined, observabilityDetails
|
|
2565
|
+
return responseWithErrorObservability(c.json(toErrorResponse(error, undefined, observabilityDetails, undefined, errorEnvelopeLocalization({
|
|
2566
|
+
catalogs: localeCatalogs,
|
|
2567
|
+
requestHeaders: c.req.raw.headers,
|
|
2568
|
+
})), 404), observabilityDetails);
|
|
2374
2569
|
});
|
|
2570
|
+
// Liveness. Deliberately static and engine-blind: generated manifests point
|
|
2571
|
+
// liveness at this route, so making it depend on engine reachability would
|
|
2572
|
+
// restart every provider pod on one engine incident. Engine state belongs to
|
|
2573
|
+
// /readyz, which manifests wire to readiness and startup only.
|
|
2375
2574
|
app.get("/health", (c) => c.json({
|
|
2376
2575
|
status: "ok",
|
|
2377
2576
|
provider: provider.id,
|
|
2378
2577
|
version: provider.version,
|
|
2379
2578
|
}));
|
|
2579
|
+
// Readiness. Reports the boot-resolved attachment; does not probe the engine
|
|
2580
|
+
// per call, so it cannot amplify an engine incident into request load.
|
|
2581
|
+
app.get("/readyz", (c) => c.json({
|
|
2582
|
+
status: engineAttached ? "ok" : "unavailable",
|
|
2583
|
+
provider: provider.id,
|
|
2584
|
+
version: provider.version,
|
|
2585
|
+
engine: {
|
|
2586
|
+
// The resolution, not the raw engine `kind`: normalized, so this
|
|
2587
|
+
// body and the `provider_engine_mode` boot event never disagree.
|
|
2588
|
+
mode: engineSelection.resolution.mode,
|
|
2589
|
+
attached: engineAttached,
|
|
2590
|
+
},
|
|
2591
|
+
}, engineAttached ? 200 : 503));
|
|
2380
2592
|
app.post(STATEFUL_INTERNAL_OPERATIONS_ROUTE, async (c) => {
|
|
2381
2593
|
let rawBodyText = "";
|
|
2382
2594
|
let rawBody;
|
|
@@ -2482,7 +2694,10 @@ function createServerAppWithCapabilityModules(provider, serverOptions, capabilit
|
|
|
2482
2694
|
requestId: request.requestId,
|
|
2483
2695
|
operationId,
|
|
2484
2696
|
headers: request.headers ?? {},
|
|
2485
|
-
correlation: {
|
|
2697
|
+
correlation: {
|
|
2698
|
+
connectionId: envelope.connectionId,
|
|
2699
|
+
tenantId: resolveOperationTenantId(request),
|
|
2700
|
+
},
|
|
2486
2701
|
});
|
|
2487
2702
|
const response = await requestScope.run(async () => {
|
|
2488
2703
|
const ctx = createProviderContext(provider, request, operationId, options, state, requestScope, signal);
|
|
@@ -2517,7 +2732,12 @@ function createServerAppWithCapabilityModules(provider, serverOptions, capabilit
|
|
|
2517
2732
|
...(requestId ? { requestId } : {}),
|
|
2518
2733
|
});
|
|
2519
2734
|
const observabilityDetails = errorObservabilityDetails(error, declaredErrorCode);
|
|
2520
|
-
const response = c.json(toErrorResponse(error, requestId, observabilityDetails, requestScope.redact
|
|
2735
|
+
const response = c.json(toErrorResponse(error, requestId, observabilityDetails, requestScope.redact, errorEnvelopeLocalization({
|
|
2736
|
+
catalogs: localeCatalogs,
|
|
2737
|
+
requestHeaders: c.req.raw.headers,
|
|
2738
|
+
rawBody,
|
|
2739
|
+
...(declaredErrorCode ? { declaredErrorCode } : {}),
|
|
2740
|
+
})), status);
|
|
2521
2741
|
return finalizeRequestResponse(requestScope, response, {
|
|
2522
2742
|
kind: "failed",
|
|
2523
2743
|
status,
|
|
@@ -2551,7 +2771,10 @@ function createServerAppWithCapabilityModules(provider, serverOptions, capabilit
|
|
|
2551
2771
|
requestScope.enrich({
|
|
2552
2772
|
requestId: body.requestId,
|
|
2553
2773
|
headers: body.headers,
|
|
2554
|
-
correlation: {
|
|
2774
|
+
correlation: {
|
|
2775
|
+
connectionId: resolveOperationConnectionId(body),
|
|
2776
|
+
tenantId: resolveOperationTenantId(body),
|
|
2777
|
+
},
|
|
2555
2778
|
});
|
|
2556
2779
|
const streaming = provider.operations[operation]?.transport?.kind
|
|
2557
2780
|
? provider.operations[operation]?.transport?.kind !== "json"
|
|
@@ -2581,7 +2804,12 @@ function createServerAppWithCapabilityModules(provider, serverOptions, capabilit
|
|
|
2581
2804
|
const requestId = extractRequestId(rawBody);
|
|
2582
2805
|
requestScope.enrich({ ...(requestId ? { requestId } : {}) });
|
|
2583
2806
|
const observabilityDetails = errorObservabilityDetails(error, declaredErrorCode);
|
|
2584
|
-
const response = c.json(toErrorResponse(error, requestId, observabilityDetails, requestScope.redact
|
|
2807
|
+
const response = c.json(toErrorResponse(error, requestId, observabilityDetails, requestScope.redact, errorEnvelopeLocalization({
|
|
2808
|
+
catalogs: localeCatalogs,
|
|
2809
|
+
requestHeaders: c.req.raw.headers,
|
|
2810
|
+
rawBody,
|
|
2811
|
+
...(declaredErrorCode ? { declaredErrorCode } : {}),
|
|
2812
|
+
})), status);
|
|
2585
2813
|
return finalizeRequestResponse(requestScope, response, {
|
|
2586
2814
|
kind: "failed",
|
|
2587
2815
|
status,
|
|
@@ -2599,6 +2827,12 @@ function createServerAppWithCapabilityModules(provider, serverOptions, capabilit
|
|
|
2599
2827
|
for (const { path, flowRoute, logRoute } of authRoutes) {
|
|
2600
2828
|
app.post(path, async (c) => {
|
|
2601
2829
|
let rawBody;
|
|
2830
|
+
// Negotiated once and shared by the success and failure paths so an
|
|
2831
|
+
// auth turn and an error envelope from the same request agree.
|
|
2832
|
+
let localization = errorEnvelopeLocalization({
|
|
2833
|
+
catalogs: localeCatalogs,
|
|
2834
|
+
requestHeaders: c.req.raw.headers,
|
|
2835
|
+
});
|
|
2602
2836
|
const requestScope = createRequestScope({
|
|
2603
2837
|
provider,
|
|
2604
2838
|
staticSensitiveValues,
|
|
@@ -2613,6 +2847,11 @@ function createServerAppWithCapabilityModules(provider, serverOptions, capabilit
|
|
|
2613
2847
|
.clone()
|
|
2614
2848
|
.json()
|
|
2615
2849
|
.catch(() => undefined);
|
|
2850
|
+
localization = errorEnvelopeLocalization({
|
|
2851
|
+
catalogs: localeCatalogs,
|
|
2852
|
+
requestHeaders: c.req.raw.headers,
|
|
2853
|
+
rawBody,
|
|
2854
|
+
});
|
|
2616
2855
|
requestScope.seedCredentials(rawBody, "auth");
|
|
2617
2856
|
const body = withAuthRequestHeaders(AuthFlowRequestSchema.parse(rawBody), c.req.raw.headers);
|
|
2618
2857
|
requestScope.enrich({
|
|
@@ -2622,14 +2861,14 @@ function createServerAppWithCapabilityModules(provider, serverOptions, capabilit
|
|
|
2622
2861
|
correlation: {
|
|
2623
2862
|
connectionId: resolveOperationConnectionId(body),
|
|
2624
2863
|
flowId: body.flowId,
|
|
2625
|
-
tenantId: body.tenantId,
|
|
2864
|
+
tenantId: normalizeIdentifier(body.tenantId),
|
|
2626
2865
|
requestedProviderId: body.providerId !== undefined && body.providerId !== provider.id
|
|
2627
2866
|
? body.providerId
|
|
2628
2867
|
: undefined,
|
|
2629
2868
|
},
|
|
2630
2869
|
});
|
|
2631
2870
|
const response = await requestScope.run(async () => {
|
|
2632
|
-
const handled = await handleAuthFlow(provider, body, flowRoute, options, state, requestScope, c.req.raw.signal);
|
|
2871
|
+
const handled = await handleAuthFlow(provider, body, flowRoute, options, state, requestScope, localization.locale, c.req.raw.signal);
|
|
2633
2872
|
return handled instanceof Response ? handled : c.json(handled);
|
|
2634
2873
|
});
|
|
2635
2874
|
return finalizeRequestResponse(requestScope, response, {
|
|
@@ -2642,7 +2881,7 @@ function createServerAppWithCapabilityModules(provider, serverOptions, capabilit
|
|
|
2642
2881
|
const requestId = extractRequestId(rawBody);
|
|
2643
2882
|
requestScope.enrich({ ...(requestId ? { requestId } : {}) });
|
|
2644
2883
|
const observabilityDetails = errorObservabilityDetails(error);
|
|
2645
|
-
const response = c.json(toErrorResponse(error, requestId, observabilityDetails, requestScope.redact), status);
|
|
2884
|
+
const response = c.json(toErrorResponse(error, requestId, observabilityDetails, requestScope.redact, localization), status);
|
|
2646
2885
|
return finalizeRequestResponse(requestScope, response, {
|
|
2647
2886
|
kind: "failed",
|
|
2648
2887
|
status,
|
|
@@ -2704,13 +2943,18 @@ export async function serve(provider, options = {}) {
|
|
|
2704
2943
|
const configuredTimeoutMs = shutdownTimeout(options.shutdown?.timeoutMs ?? DEFAULT_SHUTDOWN_TIMEOUT_MS);
|
|
2705
2944
|
const configuredSignals = resolveShutdownSignals(options.shutdown?.signals ?? true);
|
|
2706
2945
|
const selfTestSecrets = resolveSelfTestMasterSecrets();
|
|
2946
|
+
// Resolve the engine here so the boot event reports the truthful source
|
|
2947
|
+
// (option/env/default) and the app is handed the engine already selected —
|
|
2948
|
+
// one resolution per process, not one per app construction.
|
|
2949
|
+
const engineSelection = resolveServerEngine(options);
|
|
2707
2950
|
const serverAppOptions = {
|
|
2708
2951
|
logger: options.logger,
|
|
2709
|
-
engine:
|
|
2952
|
+
engine: engineSelection.engine,
|
|
2710
2953
|
files: options.files,
|
|
2711
2954
|
ocr: options.ocr,
|
|
2712
2955
|
stt: options.stt,
|
|
2713
2956
|
resolver: options.resolver,
|
|
2957
|
+
localeCatalogs: options.localeCatalogs,
|
|
2714
2958
|
state: options.state,
|
|
2715
2959
|
allowMemoryStateFallback: options.allowMemoryStateFallback,
|
|
2716
2960
|
operationExecutor: options.operationExecutor,
|
|
@@ -2721,6 +2965,9 @@ export async function serve(provider, options = {}) {
|
|
|
2721
2965
|
createServerAppAsync(provider, serverAppOptions),
|
|
2722
2966
|
selfTestSecrets ? import("./self-test.js") : undefined,
|
|
2723
2967
|
]);
|
|
2968
|
+
// One structured line per process boot, before the listener binds: the fleet
|
|
2969
|
+
// audit (ADR-0011 migration) counts these.
|
|
2970
|
+
logger(engineModeLogEvent(provider, engineSelection.resolution, !isUnavailableProviderEngine(engineSelection.engine)));
|
|
2724
2971
|
const servers = [];
|
|
2725
2972
|
try {
|
|
2726
2973
|
servers.push(bunRuntime.serve({
|