@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,77 @@
|
|
|
1
|
+
import type { SttContext } from "../types.js";
|
|
2
|
+
import { type ClosedEnum, type SpanIndex, type TelemetryContributor } from "./request-telemetry.js";
|
|
3
|
+
export type SttTelemetryBackend = "cloudflare-workers-ai" | "custom" | "unavailable";
|
|
4
|
+
export type SttTelemetryEngine = "workers-ai" | "custom";
|
|
5
|
+
export type SttTelemetryErrorCode = "STT_UNAVAILABLE" | "UNSUPPORTED_STT_BACKEND" | "STT_UPSTREAM_FAILED" | "STT_AUDIO_TOO_LARGE" | "UNSUPPORTED_STT_OPTION" | "INVALID_STT_AUDIO" | "INVALID_STT_VERIFICATION_CODE_OPTIONS" | "NO_CODE_FOUND" | "AMBIGUOUS_CODE" | "transport_network_error" | "transport_timeout" | "other";
|
|
6
|
+
export type SttTelemetryModel = "whisper-large-v3-turbo";
|
|
7
|
+
export type SttTelemetryEvent = {
|
|
8
|
+
backend: SttTelemetryBackend;
|
|
9
|
+
engine: SttTelemetryEngine;
|
|
10
|
+
model?: string;
|
|
11
|
+
ms: number;
|
|
12
|
+
status?: number;
|
|
13
|
+
audioBytes?: number;
|
|
14
|
+
durationMs?: number;
|
|
15
|
+
usage?: number;
|
|
16
|
+
warnings?: number;
|
|
17
|
+
errorCode?: SttTelemetryErrorCode;
|
|
18
|
+
diagnostics?: string;
|
|
19
|
+
};
|
|
20
|
+
export interface SttTelemetrySink {
|
|
21
|
+
record(event: SttTelemetryEvent): void;
|
|
22
|
+
markTelemetryFailed?(): void;
|
|
23
|
+
}
|
|
24
|
+
export type SttTelemetryLogPayload = {
|
|
25
|
+
telemetryFailed?: true;
|
|
26
|
+
diagnostics?: string[];
|
|
27
|
+
backend: SttTelemetryBackend;
|
|
28
|
+
engine: SttTelemetryEngine;
|
|
29
|
+
model?: string;
|
|
30
|
+
ms: number;
|
|
31
|
+
status?: number;
|
|
32
|
+
audioBytes: number;
|
|
33
|
+
durationMs: number;
|
|
34
|
+
usage: number;
|
|
35
|
+
warnings: number;
|
|
36
|
+
lastErrorCode?: SttTelemetryErrorCode;
|
|
37
|
+
samples?: Array<Omit<SttTelemetryEvent, "backend" | "engine" | "model" | "diagnostics">>;
|
|
38
|
+
samplesDropped?: number;
|
|
39
|
+
};
|
|
40
|
+
export type SttTelemetryHeaderPayload = {
|
|
41
|
+
backend: ClosedEnum<SttTelemetryBackend>;
|
|
42
|
+
engine: ClosedEnum<SttTelemetryEngine>;
|
|
43
|
+
model?: ClosedEnum<SttTelemetryModel>;
|
|
44
|
+
ms: number;
|
|
45
|
+
status?: number;
|
|
46
|
+
audioBytes: number;
|
|
47
|
+
durationMs: number;
|
|
48
|
+
usage: number;
|
|
49
|
+
warnings: number;
|
|
50
|
+
lastErrorCode?: ClosedEnum<SttTelemetryErrorCode>;
|
|
51
|
+
samples?: Array<{
|
|
52
|
+
ms: number;
|
|
53
|
+
status?: number;
|
|
54
|
+
audioBytes?: number;
|
|
55
|
+
durationMs?: number;
|
|
56
|
+
usage?: number;
|
|
57
|
+
warnings?: number;
|
|
58
|
+
errorCode?: ClosedEnum<SttTelemetryErrorCode>;
|
|
59
|
+
}>;
|
|
60
|
+
samplesDropped?: number;
|
|
61
|
+
};
|
|
62
|
+
export declare class SttTelemetryCollector implements SttTelemetrySink, TelemetryContributor<SttTelemetryLogPayload, SttTelemetryHeaderPayload> {
|
|
63
|
+
#private;
|
|
64
|
+
readonly key: "stt";
|
|
65
|
+
constructor(options?: {
|
|
66
|
+
redact?: (text: string) => string;
|
|
67
|
+
});
|
|
68
|
+
markTelemetryFailed(): void;
|
|
69
|
+
record(event: SttTelemetryEvent): void;
|
|
70
|
+
toLogPayload(_spans: SpanIndex): SttTelemetryLogPayload | undefined;
|
|
71
|
+
toHeaderPayload(log: SttTelemetryLogPayload): SttTelemetryHeaderPayload;
|
|
72
|
+
}
|
|
73
|
+
export declare function bindSttTelemetry(context: SttContext, sink: SttTelemetrySink, options?: {
|
|
74
|
+
backend?: SttTelemetryBackend;
|
|
75
|
+
engine?: SttTelemetryEngine;
|
|
76
|
+
model?: string;
|
|
77
|
+
}): SttContext;
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { add, capabilityErrorText, capabilityFacts, capabilityMetadata, capabilityText, inputBytes, integer, observeCapability, registerCapabilityInput, } from "./capability-telemetry.js";
|
|
2
|
+
import { closedEnum, } from "./request-telemetry.js";
|
|
3
|
+
const ERROR_CODES = new Set([
|
|
4
|
+
"STT_UNAVAILABLE",
|
|
5
|
+
"UNSUPPORTED_STT_BACKEND",
|
|
6
|
+
"STT_UPSTREAM_FAILED",
|
|
7
|
+
"STT_AUDIO_TOO_LARGE",
|
|
8
|
+
"UNSUPPORTED_STT_OPTION",
|
|
9
|
+
"INVALID_STT_AUDIO",
|
|
10
|
+
"INVALID_STT_VERIFICATION_CODE_OPTIONS",
|
|
11
|
+
"NO_CODE_FOUND",
|
|
12
|
+
"AMBIGUOUS_CODE",
|
|
13
|
+
"transport_network_error",
|
|
14
|
+
"transport_timeout",
|
|
15
|
+
"other",
|
|
16
|
+
]);
|
|
17
|
+
const MODELS = new Map([
|
|
18
|
+
["@cf/openai/whisper-large-v3-turbo", "whisper-large-v3-turbo"],
|
|
19
|
+
]);
|
|
20
|
+
function errorCode(error) {
|
|
21
|
+
const code = error && typeof error === "object" && "code" in error ? error.code : undefined;
|
|
22
|
+
return typeof code === "string" && ERROR_CODES.has(code)
|
|
23
|
+
? code
|
|
24
|
+
: "other";
|
|
25
|
+
}
|
|
26
|
+
export class SttTelemetryCollector {
|
|
27
|
+
key = "stt";
|
|
28
|
+
#redact;
|
|
29
|
+
#samples = [];
|
|
30
|
+
#summary;
|
|
31
|
+
#diagnostics = [];
|
|
32
|
+
#dropped = 0;
|
|
33
|
+
#failed = false;
|
|
34
|
+
constructor(options = {}) {
|
|
35
|
+
this.#redact = options.redact;
|
|
36
|
+
}
|
|
37
|
+
markTelemetryFailed() {
|
|
38
|
+
this.#failed = true;
|
|
39
|
+
this.#summary ??= {
|
|
40
|
+
backend: "custom",
|
|
41
|
+
engine: "custom",
|
|
42
|
+
ms: 0,
|
|
43
|
+
audioBytes: 0,
|
|
44
|
+
durationMs: 0,
|
|
45
|
+
usage: 0,
|
|
46
|
+
warnings: 0,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
record(event) {
|
|
50
|
+
const sample = {
|
|
51
|
+
ms: integer(event.ms),
|
|
52
|
+
...(event.status === undefined ? {} : { status: integer(event.status) }),
|
|
53
|
+
...(event.audioBytes === undefined ? {} : { audioBytes: integer(event.audioBytes) }),
|
|
54
|
+
...(event.durationMs === undefined ? {} : { durationMs: integer(event.durationMs) }),
|
|
55
|
+
...(event.usage === undefined ? {} : { usage: integer(event.usage) }),
|
|
56
|
+
...(event.warnings === undefined ? {} : { warnings: integer(event.warnings) }),
|
|
57
|
+
...(event.errorCode ? { errorCode: event.errorCode } : {}),
|
|
58
|
+
...(event.diagnostics === undefined
|
|
59
|
+
? {}
|
|
60
|
+
: { diagnostics: capabilityText(event.diagnostics, this.#redact, true) }),
|
|
61
|
+
};
|
|
62
|
+
const prior = this.#summary;
|
|
63
|
+
this.#summary = {
|
|
64
|
+
backend: event.backend,
|
|
65
|
+
engine: event.engine,
|
|
66
|
+
...(event.model === undefined ? {} : { model: capabilityText(event.model, this.#redact) }),
|
|
67
|
+
ms: add(prior?.ms ?? 0, sample.ms),
|
|
68
|
+
...(sample.status === undefined ? {} : { status: sample.status }),
|
|
69
|
+
audioBytes: add(prior?.audioBytes ?? 0, sample.audioBytes ?? 0),
|
|
70
|
+
durationMs: add(prior?.durationMs ?? 0, sample.durationMs ?? 0),
|
|
71
|
+
usage: add(prior?.usage ?? 0, sample.usage ?? 0),
|
|
72
|
+
warnings: add(prior?.warnings ?? 0, sample.warnings ?? 0),
|
|
73
|
+
...(event.errorCode ? { lastErrorCode: event.errorCode } : {}),
|
|
74
|
+
};
|
|
75
|
+
if (this.#samples.length < 24) {
|
|
76
|
+
const { diagnostics, ...closedSample } = sample;
|
|
77
|
+
this.#samples.push(closedSample);
|
|
78
|
+
if (diagnostics !== undefined)
|
|
79
|
+
this.#diagnostics.push(diagnostics);
|
|
80
|
+
}
|
|
81
|
+
else
|
|
82
|
+
this.#dropped = add(this.#dropped, 1);
|
|
83
|
+
}
|
|
84
|
+
toLogPayload(_spans) {
|
|
85
|
+
if (!this.#summary)
|
|
86
|
+
return undefined;
|
|
87
|
+
return {
|
|
88
|
+
...this.#summary,
|
|
89
|
+
...(this.#diagnostics.length ? { diagnostics: [...this.#diagnostics] } : {}),
|
|
90
|
+
...(this.#failed ? { telemetryFailed: true } : {}),
|
|
91
|
+
samples: this.#samples.map((s) => ({ ...s })),
|
|
92
|
+
...(this.#dropped ? { samplesDropped: this.#dropped } : {}),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
toHeaderPayload(log) {
|
|
96
|
+
return {
|
|
97
|
+
backend: closedEnum(log.backend),
|
|
98
|
+
engine: closedEnum(log.engine),
|
|
99
|
+
...(log.model && MODELS.has(log.model) ? { model: closedEnum(MODELS.get(log.model)) } : {}),
|
|
100
|
+
ms: log.ms,
|
|
101
|
+
...(log.status === undefined ? {} : { status: log.status }),
|
|
102
|
+
audioBytes: log.audioBytes,
|
|
103
|
+
durationMs: log.durationMs,
|
|
104
|
+
usage: log.usage,
|
|
105
|
+
warnings: log.warnings,
|
|
106
|
+
...(log.lastErrorCode ? { lastErrorCode: closedEnum(log.lastErrorCode) } : {}),
|
|
107
|
+
...(log.samples
|
|
108
|
+
? {
|
|
109
|
+
samples: log.samples.map((s) => ({
|
|
110
|
+
ms: s.ms,
|
|
111
|
+
...(s.status === undefined ? {} : { status: s.status }),
|
|
112
|
+
...(s.audioBytes === undefined ? {} : { audioBytes: s.audioBytes }),
|
|
113
|
+
...(s.durationMs === undefined ? {} : { durationMs: s.durationMs }),
|
|
114
|
+
...(s.usage === undefined ? {} : { usage: s.usage }),
|
|
115
|
+
...(s.warnings === undefined ? {} : { warnings: s.warnings }),
|
|
116
|
+
...(s.errorCode ? { errorCode: closedEnum(s.errorCode) } : {}),
|
|
117
|
+
})),
|
|
118
|
+
}
|
|
119
|
+
: {}),
|
|
120
|
+
...(log.samplesDropped ? { samplesDropped: log.samplesDropped } : {}),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
export function bindSttTelemetry(context, sink, options = {}) {
|
|
125
|
+
const metadata = capabilityMetadata(context);
|
|
126
|
+
const backend = options.backend ?? metadata?.backend ?? "custom";
|
|
127
|
+
const engine = options.engine ?? metadata?.engine ?? "custom";
|
|
128
|
+
const model = options.model ?? metadata?.model;
|
|
129
|
+
async function run(input, operation) {
|
|
130
|
+
const started = performance.now();
|
|
131
|
+
const facts = {};
|
|
132
|
+
observeCapability(sink, () => registerCapabilityInput(input));
|
|
133
|
+
let result;
|
|
134
|
+
try {
|
|
135
|
+
result = await capabilityFacts.run(facts, operation);
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
observeCapability(sink, () => {
|
|
139
|
+
const status = error &&
|
|
140
|
+
typeof error === "object" &&
|
|
141
|
+
"status" in error &&
|
|
142
|
+
typeof error.status === "number"
|
|
143
|
+
? error.status
|
|
144
|
+
: undefined;
|
|
145
|
+
return sink.record({
|
|
146
|
+
backend,
|
|
147
|
+
engine,
|
|
148
|
+
model,
|
|
149
|
+
ms: performance.now() - started,
|
|
150
|
+
status: facts.status ?? status,
|
|
151
|
+
audioBytes: inputBytes(input),
|
|
152
|
+
errorCode: errorCode(error),
|
|
153
|
+
diagnostics: `${capabilityErrorText(error)} ${facts.diagnostics ?? ""}`,
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
throw error;
|
|
157
|
+
}
|
|
158
|
+
observeCapability(sink, () => sink.record({
|
|
159
|
+
backend,
|
|
160
|
+
engine,
|
|
161
|
+
model: model,
|
|
162
|
+
ms: performance.now() - started,
|
|
163
|
+
status: facts.status,
|
|
164
|
+
audioBytes: result.usage?.audioBytes ?? inputBytes(input),
|
|
165
|
+
durationMs: result.durationMs,
|
|
166
|
+
usage: result.usage?.audioDurationMs,
|
|
167
|
+
warnings: result.warnings?.length ?? 0,
|
|
168
|
+
}));
|
|
169
|
+
return result;
|
|
170
|
+
}
|
|
171
|
+
return {
|
|
172
|
+
...context,
|
|
173
|
+
transcribe: (request) => run(request.audio, () => context.transcribe(request)),
|
|
174
|
+
extractVerificationCode: (text, opts) => context.extractVerificationCode(text, opts),
|
|
175
|
+
};
|
|
176
|
+
}
|
package/dist/runtime/stt.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { readDiagnosticEnv } from "./diagnostic-env.js";
|
|
2
1
|
import { ProviderError, TransportError, ValidationError } from "../errors.js";
|
|
2
|
+
import { readCapabilityErrorBody } from "./capability-response.js";
|
|
3
|
+
import { captureCapability, registerCapabilityInput, tagCapability, } from "./capability-telemetry.js";
|
|
4
|
+
import { readDiagnosticEnv, registerDiagnosticValue } from "./diagnostic-env.js";
|
|
3
5
|
import { createTimeoutController, isTimeoutLikeError } from "./timeout.js";
|
|
4
6
|
export const APIFUSE__STT__BACKEND_ENV = "APIFUSE__STT__BACKEND";
|
|
5
7
|
export const APIFUSE__STT__MODEL_ENV = "APIFUSE__STT__MODEL";
|
|
@@ -15,7 +17,7 @@ function providerError(message, options) {
|
|
|
15
17
|
return new ProviderError(message, options);
|
|
16
18
|
}
|
|
17
19
|
function createErrorSttClient(options) {
|
|
18
|
-
return {
|
|
20
|
+
return tagCapability({
|
|
19
21
|
async transcribe() {
|
|
20
22
|
throw providerError(options.message, {
|
|
21
23
|
code: options.code,
|
|
@@ -23,7 +25,7 @@ function createErrorSttClient(options) {
|
|
|
23
25
|
});
|
|
24
26
|
},
|
|
25
27
|
extractVerificationCode,
|
|
26
|
-
};
|
|
28
|
+
}, { backend: "unavailable", engine: "custom" });
|
|
27
29
|
}
|
|
28
30
|
export function createUnsupportedSttClient(reason) {
|
|
29
31
|
return createErrorSttClient({
|
|
@@ -209,8 +211,11 @@ function toSttTranscript(payload, audioBytes) {
|
|
|
209
211
|
export function createCloudflareWorkersAiSttClient(options) {
|
|
210
212
|
const model = options.model ?? DEFAULT_CLOUDFLARE_WORKERS_AI_STT_MODEL;
|
|
211
213
|
const runFetch = options.fetch ?? fetch;
|
|
212
|
-
return {
|
|
214
|
+
return tagCapability({
|
|
213
215
|
async transcribe(request) {
|
|
216
|
+
registerCapabilityInput(request.audio);
|
|
217
|
+
registerDiagnosticValue(options.apiToken);
|
|
218
|
+
registerDiagnosticValue(`Bearer ${options.apiToken}`);
|
|
214
219
|
const warnings = [];
|
|
215
220
|
if (request.initialPrompt && effectivePromptPolicy(request) !== "custom-hint") {
|
|
216
221
|
const warning = warnOrThrowUnsupportedOption(request, "initialPrompt is honored only when promptPolicy is custom-hint");
|
|
@@ -235,16 +240,20 @@ export function createCloudflareWorkersAiSttClient(options) {
|
|
|
235
240
|
catch (error) {
|
|
236
241
|
throw toSttTransportError(error);
|
|
237
242
|
}
|
|
238
|
-
|
|
243
|
+
captureCapability({ status: response.status });
|
|
239
244
|
if (!response.ok) {
|
|
245
|
+
const echoed = await readCapabilityErrorBody(response, timeout.controller.signal);
|
|
246
|
+
captureCapability({ diagnostics: echoed });
|
|
240
247
|
throw new TransportError("STT upstream request failed", {
|
|
241
248
|
code: "STT_UPSTREAM_FAILED",
|
|
242
249
|
status: response.status,
|
|
243
250
|
upstreamStatus: response.status,
|
|
244
251
|
});
|
|
245
252
|
}
|
|
253
|
+
const payload = await response.json().catch(() => undefined);
|
|
246
254
|
const envelope = unknownRecord(payload);
|
|
247
255
|
if (envelope?.success === false) {
|
|
256
|
+
captureCapability({ diagnostics: JSON.stringify(payload) });
|
|
248
257
|
throw new TransportError("STT upstream returned an error", {
|
|
249
258
|
code: "STT_UPSTREAM_FAILED",
|
|
250
259
|
status: 502,
|
|
@@ -270,7 +279,7 @@ export function createCloudflareWorkersAiSttClient(options) {
|
|
|
270
279
|
}
|
|
271
280
|
},
|
|
272
281
|
extractVerificationCode,
|
|
273
|
-
};
|
|
282
|
+
}, { backend: "cloudflare-workers-ai", engine: "workers-ai", model });
|
|
274
283
|
}
|
|
275
284
|
const EN_DIGITS = {
|
|
276
285
|
zero: "0",
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type DiagnosticRedactor } from "../runtime/diagnostic-redactor.js";
|
|
2
|
+
/**
|
|
3
|
+
* Bounded, whitelist-shaped stack frames for masked (>=500) provider failures.
|
|
4
|
+
*
|
|
5
|
+
* `sanitizeDiagnosticText` is a blacklist scrubber for free text: a V8/Bun
|
|
6
|
+
* frame such as `at inner (/srv/app/probe.ts:3:30)` comes out as
|
|
7
|
+
* `at inner ([REDACTED])`, and even a bare `serve-implementation.ts:2039:12`
|
|
8
|
+
* trips the opaque-token heuristics. Stack frames therefore never go through
|
|
9
|
+
* it. Instead each frame is parsed against a strict grammar and re-emitted
|
|
10
|
+
* from its parts only: an optional `async`/`new` marker, the function name
|
|
11
|
+
* (identifier characters only), the file *basename* (never a filesystem
|
|
12
|
+
* directory, URL, or drive letter) and the numeric line:column. The sole
|
|
13
|
+
* exception is an engine-internal location (`native`, or a `node:` module id
|
|
14
|
+
* of identifier-shaped segments), which is kept verbatim because it names no
|
|
15
|
+
* deployment path. Frames that do not fit the grammar (eval frames, frames
|
|
16
|
+
* without a location, oversized lines) are dropped rather than passed
|
|
17
|
+
* through.
|
|
18
|
+
*/
|
|
19
|
+
export declare const MAX_PROVIDER_ERROR_STACK_FRAMES = 5;
|
|
20
|
+
/** Parses one `at ...` line into `[async |new ][fn ](basename:line:col)`, or undefined. */
|
|
21
|
+
export declare function parseProviderErrorStackFrame(line: string): string | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Up to {@link MAX_PROVIDER_ERROR_STACK_FRAMES} whitelist-shaped frames from
|
|
24
|
+
* `error.stack`, or undefined when nothing parses. For an engine-formatted
|
|
25
|
+
* stack the header (which embeds the current `message`) is located and
|
|
26
|
+
* stripped first, so a provider-controlled *message* containing newlines
|
|
27
|
+
* cannot inject frame-shaped text (no header match, no frames). A provider
|
|
28
|
+
* that overwrites `stack` or `name` outright can still put grammar-shaped
|
|
29
|
+
* frames in the record: the field is a diagnostic hint, not an attested
|
|
30
|
+
* location, and the whitelist plus the redactor bound what it can carry.
|
|
31
|
+
* Each emitted frame still passes
|
|
32
|
+
* through the request redactor so a registered secret that happens to appear
|
|
33
|
+
* in a function or file name is masked (fail-closed to `[REDACTION_FAILED]`).
|
|
34
|
+
*/
|
|
35
|
+
export declare function providerErrorStackFrames(error: unknown, redact?: DiagnosticRedactor): string[] | undefined;
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { redactDiagnosticText } from "../runtime/diagnostic-redactor.js";
|
|
2
|
+
/**
|
|
3
|
+
* Bounded, whitelist-shaped stack frames for masked (>=500) provider failures.
|
|
4
|
+
*
|
|
5
|
+
* `sanitizeDiagnosticText` is a blacklist scrubber for free text: a V8/Bun
|
|
6
|
+
* frame such as `at inner (/srv/app/probe.ts:3:30)` comes out as
|
|
7
|
+
* `at inner ([REDACTED])`, and even a bare `serve-implementation.ts:2039:12`
|
|
8
|
+
* trips the opaque-token heuristics. Stack frames therefore never go through
|
|
9
|
+
* it. Instead each frame is parsed against a strict grammar and re-emitted
|
|
10
|
+
* from its parts only: an optional `async`/`new` marker, the function name
|
|
11
|
+
* (identifier characters only), the file *basename* (never a filesystem
|
|
12
|
+
* directory, URL, or drive letter) and the numeric line:column. The sole
|
|
13
|
+
* exception is an engine-internal location (`native`, or a `node:` module id
|
|
14
|
+
* of identifier-shaped segments), which is kept verbatim because it names no
|
|
15
|
+
* deployment path. Frames that do not fit the grammar (eval frames, frames
|
|
16
|
+
* without a location, oversized lines) are dropped rather than passed
|
|
17
|
+
* through.
|
|
18
|
+
*/
|
|
19
|
+
export const MAX_PROVIDER_ERROR_STACK_FRAMES = 5;
|
|
20
|
+
const MAX_STACK_SCAN_CHARS = 16 * 1024;
|
|
21
|
+
const MAX_STACK_SCAN_LINES = 64;
|
|
22
|
+
const MAX_STACK_LINE_CHARS = 1024;
|
|
23
|
+
const FRAME_LINE = /^\s+at\s+(\S.*)$/;
|
|
24
|
+
const FRAME_MODIFIER = /^(async|new)\s+(.*)$/;
|
|
25
|
+
const FRAME_FUNCTION_NAME = /^[\w$.<>[\] #]{1,80}$/;
|
|
26
|
+
const FRAME_LOCATION = /^(.*):(\d{1,7}):(\d{1,7})$/;
|
|
27
|
+
const MAX_NODE_MODULE_ID_CHARS = 128;
|
|
28
|
+
// Engine-internal module ids only: `node:` plus `/`-separated identifier-shaped
|
|
29
|
+
// segments (`node:async_hooks`, `node:internal/process/task_queues`). Every
|
|
30
|
+
// segment must start with a letter or `_`, so `..` traversal and dotfile
|
|
31
|
+
// segments cannot ride through this branch.
|
|
32
|
+
const FRAME_NODE_MODULE = /^node:[A-Za-z_][\w.-]{0,40}(?:\/[A-Za-z_][\w.-]{0,40}){0,7}$/;
|
|
33
|
+
const FRAME_BASENAME = /^[\w.$-]{1,120}$/;
|
|
34
|
+
// A basename of dots only (`.`, `..`, `...`) names no file.
|
|
35
|
+
const FRAME_BASENAME_HAS_NAME = /[^.]/;
|
|
36
|
+
function parseFunctionName(raw) {
|
|
37
|
+
let rest = raw.trim();
|
|
38
|
+
let modifier;
|
|
39
|
+
const modified = FRAME_MODIFIER.exec(rest);
|
|
40
|
+
if (modified) {
|
|
41
|
+
modifier = modified[1];
|
|
42
|
+
rest = modified[2].trim();
|
|
43
|
+
}
|
|
44
|
+
if (rest.length === 0)
|
|
45
|
+
return { modifier };
|
|
46
|
+
if (!FRAME_FUNCTION_NAME.test(rest))
|
|
47
|
+
return undefined;
|
|
48
|
+
return { modifier, name: rest };
|
|
49
|
+
}
|
|
50
|
+
function parseLocation(raw) {
|
|
51
|
+
if (/[\s()]/.test(raw))
|
|
52
|
+
return undefined;
|
|
53
|
+
const located = FRAME_LOCATION.exec(raw);
|
|
54
|
+
if (!located)
|
|
55
|
+
return undefined;
|
|
56
|
+
const [, path, line, column] = located;
|
|
57
|
+
let file;
|
|
58
|
+
if (path === "native" ||
|
|
59
|
+
(path.length <= MAX_NODE_MODULE_ID_CHARS && FRAME_NODE_MODULE.test(path))) {
|
|
60
|
+
// Not filesystem paths: engine-internal module ids carry no deployment
|
|
61
|
+
// information. This is the one branch that keeps a `/`, and the grammar
|
|
62
|
+
// above bounds it to identifier segments.
|
|
63
|
+
file = path;
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
const separator = Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\"));
|
|
67
|
+
const basename = separator >= 0 ? path.slice(separator + 1) : path;
|
|
68
|
+
if (!FRAME_BASENAME.test(basename))
|
|
69
|
+
return undefined;
|
|
70
|
+
// `.` and `..` pass the basename character class but name no file: they
|
|
71
|
+
// are the traversal tokens the grammar exists to exclude, so a path such
|
|
72
|
+
// as `/srv/app/..:1:1` must not be emitted as `..:1:1`.
|
|
73
|
+
if (!FRAME_BASENAME_HAS_NAME.test(basename))
|
|
74
|
+
return undefined;
|
|
75
|
+
file = basename;
|
|
76
|
+
}
|
|
77
|
+
return `${file}:${line}:${column}`;
|
|
78
|
+
}
|
|
79
|
+
/** Parses one `at ...` line into `[async |new ][fn ](basename:line:col)`, or undefined. */
|
|
80
|
+
export function parseProviderErrorStackFrame(line) {
|
|
81
|
+
if (line.length > MAX_STACK_LINE_CHARS)
|
|
82
|
+
return undefined;
|
|
83
|
+
const frame = FRAME_LINE.exec(line);
|
|
84
|
+
if (!frame)
|
|
85
|
+
return undefined;
|
|
86
|
+
const rest = frame[1].trimEnd();
|
|
87
|
+
let functionPart;
|
|
88
|
+
let locationPart;
|
|
89
|
+
if (rest.endsWith(")")) {
|
|
90
|
+
const open = rest.lastIndexOf("(");
|
|
91
|
+
if (open < 0)
|
|
92
|
+
return undefined;
|
|
93
|
+
functionPart = rest.slice(0, open);
|
|
94
|
+
locationPart = rest.slice(open + 1, -1);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
// A frame with no parenthesized location still carries its `async`/`new`
|
|
98
|
+
// modifier inline (`at async file:///app/index.mjs:12:3`, emitted by V8
|
|
99
|
+
// for an anonymous async frame such as a module's top-level await).
|
|
100
|
+
// Split it off here: `parseLocation` rejects anything containing
|
|
101
|
+
// whitespace, so leaving it attached dropped the whole frame.
|
|
102
|
+
const modified = FRAME_MODIFIER.exec(rest);
|
|
103
|
+
functionPart = modified ? modified[1] : "";
|
|
104
|
+
locationPart = modified ? modified[2].trim() : rest;
|
|
105
|
+
}
|
|
106
|
+
// Eval frames nest parentheses inside the function part; never pass them through.
|
|
107
|
+
if (/[()]/.test(functionPart))
|
|
108
|
+
return undefined;
|
|
109
|
+
const location = parseLocation(locationPart);
|
|
110
|
+
if (!location)
|
|
111
|
+
return undefined;
|
|
112
|
+
const fn = parseFunctionName(functionPart);
|
|
113
|
+
if (!fn)
|
|
114
|
+
return undefined;
|
|
115
|
+
const prefix = [fn.modifier, fn.name].filter((part) => part !== undefined).join(" ");
|
|
116
|
+
return prefix.length > 0 ? `${prefix} (${location})` : `(${location})`;
|
|
117
|
+
}
|
|
118
|
+
// V8 (Node >= 21) installs `stack` as a shared native accessor pair on every
|
|
119
|
+
// Error instance; JSC (Bun) installs a data property. Capture the engine's own
|
|
120
|
+
// accessor once so a provider-defined accessor (a different function object) is
|
|
121
|
+
// still rejected while the engine's is trusted. The engine accessor itself can
|
|
122
|
+
// call a process-global `Error.prepareStackTrace` hook, a process-wide trust
|
|
123
|
+
// boundary this module cannot narrow: a provider that installs one already
|
|
124
|
+
// reshapes `stack` for every consumer, and the whitelist grammar below still
|
|
125
|
+
// bounds what the resulting text can carry.
|
|
126
|
+
const NATIVE_STACK_GETTER = Object.getOwnPropertyDescriptor(new Error(), "stack")?.get;
|
|
127
|
+
function readOwnStackString(error) {
|
|
128
|
+
// Only engine-captured stacks: a thrown plain object is provider-authored text.
|
|
129
|
+
if (!(error instanceof Error))
|
|
130
|
+
return undefined;
|
|
131
|
+
try {
|
|
132
|
+
const descriptor = Object.getOwnPropertyDescriptor(error, "stack");
|
|
133
|
+
if (descriptor === undefined)
|
|
134
|
+
return undefined;
|
|
135
|
+
let stack;
|
|
136
|
+
if (Object.hasOwn(descriptor, "value")) {
|
|
137
|
+
stack = descriptor.value;
|
|
138
|
+
}
|
|
139
|
+
else if (typeof NATIVE_STACK_GETTER === "function" &&
|
|
140
|
+
descriptor.get === NATIVE_STACK_GETTER) {
|
|
141
|
+
stack = Reflect.apply(NATIVE_STACK_GETTER, error, []);
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
// A provider-defined accessor must never run inside the logger.
|
|
145
|
+
return undefined;
|
|
146
|
+
}
|
|
147
|
+
return typeof stack === "string" ? stack : undefined;
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// Header shapes ahead of the frame block: `Name: message` (V8/JSC),
|
|
154
|
+
// `Name [CODE]: message` (node:assert), `Name` (empty message), or the bare
|
|
155
|
+
// message (Playwright rewrites `stack` as message-first). The message itself
|
|
156
|
+
// is matched verbatim, so anything before it must be a short name-like prefix.
|
|
157
|
+
const HEADER_NAME_PREFIX = /^(?:[\w$][\w$ .[\]-]{0,119}: )?$/;
|
|
158
|
+
const HEADER_NAME_ONLY = /^[\w$][\w$ .[\]-]{0,119}$/;
|
|
159
|
+
/**
|
|
160
|
+
* The frame block that follows the header, or undefined when the header does
|
|
161
|
+
* not embed the current `message` followed by a newline. Fail closed there: if
|
|
162
|
+
* `message` was mutated after the stack was formatted, the original message
|
|
163
|
+
* lines are still in the string and could be parsed as forged frames. (A
|
|
164
|
+
* mutation that truncates exactly at one of the message's own newlines is
|
|
165
|
+
* indistinguishable from the string alone; the whitelist grammar and the
|
|
166
|
+
* redactor still bound what such a line can carry.)
|
|
167
|
+
*/
|
|
168
|
+
function frameBlock(stack, error) {
|
|
169
|
+
let message;
|
|
170
|
+
try {
|
|
171
|
+
message = error.message;
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
return undefined;
|
|
175
|
+
}
|
|
176
|
+
if (typeof message !== "string")
|
|
177
|
+
return undefined;
|
|
178
|
+
if (message.length === 0) {
|
|
179
|
+
const newline = stack.indexOf("\n");
|
|
180
|
+
if (newline < 0 || !HEADER_NAME_ONLY.test(stack.slice(0, newline)))
|
|
181
|
+
return undefined;
|
|
182
|
+
return stack.slice(newline + 1);
|
|
183
|
+
}
|
|
184
|
+
const at = stack.indexOf(`${message}\n`);
|
|
185
|
+
if (at < 0 || !HEADER_NAME_PREFIX.test(stack.slice(0, at)))
|
|
186
|
+
return undefined;
|
|
187
|
+
return stack.slice(at + message.length + 1);
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Up to {@link MAX_PROVIDER_ERROR_STACK_FRAMES} whitelist-shaped frames from
|
|
191
|
+
* `error.stack`, or undefined when nothing parses. For an engine-formatted
|
|
192
|
+
* stack the header (which embeds the current `message`) is located and
|
|
193
|
+
* stripped first, so a provider-controlled *message* containing newlines
|
|
194
|
+
* cannot inject frame-shaped text (no header match, no frames). A provider
|
|
195
|
+
* that overwrites `stack` or `name` outright can still put grammar-shaped
|
|
196
|
+
* frames in the record: the field is a diagnostic hint, not an attested
|
|
197
|
+
* location, and the whitelist plus the redactor bound what it can carry.
|
|
198
|
+
* Each emitted frame still passes
|
|
199
|
+
* through the request redactor so a registered secret that happens to appear
|
|
200
|
+
* in a function or file name is masked (fail-closed to `[REDACTION_FAILED]`).
|
|
201
|
+
*/
|
|
202
|
+
export function providerErrorStackFrames(error, redact) {
|
|
203
|
+
const stack = readOwnStackString(error);
|
|
204
|
+
if (stack === undefined)
|
|
205
|
+
return undefined;
|
|
206
|
+
const body = frameBlock(stack, error);
|
|
207
|
+
if (body === undefined)
|
|
208
|
+
return undefined;
|
|
209
|
+
const frames = [];
|
|
210
|
+
const lines = body.slice(0, MAX_STACK_SCAN_CHARS).split("\n", MAX_STACK_SCAN_LINES);
|
|
211
|
+
for (const line of lines) {
|
|
212
|
+
if (frames.length >= MAX_PROVIDER_ERROR_STACK_FRAMES)
|
|
213
|
+
break;
|
|
214
|
+
const frame = parseProviderErrorStackFrame(line);
|
|
215
|
+
if (frame !== undefined)
|
|
216
|
+
frames.push(redactDiagnosticText(frame, redact));
|
|
217
|
+
}
|
|
218
|
+
return frames.length > 0 ? frames : undefined;
|
|
219
|
+
}
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
|
+
export type { ProviderLocaleCatalogMap } from "../i18n/catalog.js";
|
|
2
|
+
export type { ProviderLocale, ProviderLocaleCatalog } from "../i18n/keys.js";
|
|
1
3
|
export type { ProxyCacheStatus, ProxyProtocol, ProxyUserAgentSource, ProxyVendorName, SmartproxyAllocatorBodyClass, } from "../config/loader.js";
|
|
2
4
|
export type { ProxyTelemetryHeaderPayload, ProxyHash, ProxyTelemetryLogPayload, ProxyTelemetryResolvedPayload, ProxyTelemetryUnresolvedPayload, } from "../runtime/proxy-telemetry.js";
|
|
3
5
|
export { RequestTelemetry, closedEnum, type ClosedEnum, type GatewayIngestible, type RequestTelemetryLogPayload, type SpanIndex, type TelemetryContributor, type TelemetryKey, type TenantNeutral, } from "../runtime/request-telemetry.js";
|
|
6
|
+
export { OcrTelemetryCollector, bindOcrTelemetry, type OcrTelemetryBackend, type OcrTelemetryEngine, type OcrTelemetryErrorCode, type OcrTelemetryEvent, type OcrTelemetryModel, type OcrTelemetryFinishReason, type OcrTelemetryHeaderPayload, type OcrTelemetryLogPayload, type OcrTelemetrySink, } from "../runtime/ocr-telemetry.js";
|
|
4
7
|
export { ResolverTelemetryCollector, type ResolverAttemptSample, type ResolverCacheReadTelemetryEvent, type ResolverCacheWriteTelemetryEvent, type ResolverFailoverTelemetryEvent, type ResolverIdentityTelemetryEvent, type ResolverOutcomeTelemetryEvent, type ResolverTelemetryAttemptOutcome, type ResolverTelemetryCacheStatus, type ResolverTelemetryCacheWriteReason, type ResolverTelemetryErrorClass, type ResolverTelemetryHeaderPayload, type ResolverTelemetryIdentitySource, type ResolverTelemetryLogPayload, type ResolverTelemetryOutcome, type ResolverTelemetryPhase, type ResolverTelemetrySink, type ResolverVendorAttemptTelemetryEvent, } from "../runtime/resolver-telemetry.js";
|
|
8
|
+
export { StealthTelemetryCollector, type StealthTelemetryAttemptEvent, type StealthTelemetryAttemptKind, type StealthTelemetryAttemptSample, type StealthTelemetryDiagnostics, type StealthTelemetryErrorCode, type StealthTelemetryHeaderPayload, type StealthTelemetryLogPayload, type StealthTelemetryRequestClass, type StealthTelemetrySbsdEvent, type StealthTelemetrySbsdOutcome, type StealthTelemetrySink, } from "../runtime/stealth-telemetry.js";
|
|
9
|
+
export { SttTelemetryCollector, bindSttTelemetry, type SttTelemetryBackend, type SttTelemetryEngine, type SttTelemetryErrorCode, type SttTelemetryEvent, type SttTelemetryModel, type SttTelemetryHeaderPayload, type SttTelemetryLogPayload, type SttTelemetrySink, } from "../runtime/stt-telemetry.js";
|
|
10
|
+
export { BrowserTelemetryCollector, type BrowserTelemetryErrorCode, type BrowserTelemetryHeaderPayload, type BrowserTelemetryLogPayload, type BrowserTelemetryPoolAcquireOutcome, type BrowserTelemetrySink, type BrowserTelemetrySampleName, type BrowserTelemetryEngine, } from "../runtime/browser-telemetry.js";
|
|
5
11
|
export type { ResolverVendorUnavailableReason } from "../runtime/resolver-vendors/types.js";
|
|
6
12
|
export type { Span, TraceContext } from "../runtime/trace.js";
|
|
13
|
+
export type { StealthBrowser, StealthOS, StealthProfileDescriptor } from "../types.js";
|
|
7
14
|
export { createServerApp, createServerAppAsync, ERROR_OBSERVABILITY_HEADER, type ErrorObservabilityDetails, type ProviderServerCloseOptions, type ProviderServerHandle, type ProviderErrorCauseFrame, type ProviderServerLogEvent, type ProviderServerLogger, type ProviderServerOperationExecutor, type ProviderServerOperationExecutorInput, type ProviderServerOptions, type ProviderServerStatefulForwardEnvelope, type ServeOptions, serve, } from "./serve.js";
|
|
8
15
|
export type { ProviderErrorObservability } from "../errors.js";
|
|
9
16
|
export { computeSelfTestPlanDigest, createSelfTestApp, createSelfTestAuthFlowInvoke, createSelfTestInvoke, DEFAULT_SELF_TEST_REQUEST_BUDGET_MS, isSelfTestReadOnlyOperation, PROVIDER_RUNTIME_SELF_TEST_REQUEST_BUDGET_MS_ENV, resolveSelfTestPort, SELF_TEST_AUTH_FLOW_MULTI_TURN_SKIP_REASON, SELF_TEST_AUTH_FLOW_REJECTED_SKIP_REASON, SELF_TEST_HEALTHZ_PATH, SELF_TEST_PATH, SELF_TEST_SCHEMA_VERSION, type SelfTestAppOptions, type SelfTestAuthFlowInvoke, type SelfTestAuthFlowRoute, type SelfTestCaseResult, type SelfTestCaseStatus, type SelfTestOperationInvoke, type SelfTestRequest, SelfTestRequestSchema, type SelfTestResponse, } from "./self-test.js";
|
|
@@ -12,4 +19,6 @@ export { collectSelfTestSensitiveValues, redactSelfTestText, SELF_TEST_MAX_TEXT_
|
|
|
12
19
|
export { DEFAULT_SELF_TEST_PORT, deriveSelfTestToken, PROVIDER_RUNTIME_SELF_TEST_MASTER_SECRET_ENV, PROVIDER_RUNTIME_SELF_TEST_MASTER_SECRET_PREVIOUS_ENV, PROVIDER_RUNTIME_SELF_TEST_PORT_ENV, resolveSelfTestMasterSecrets, type SelfTestMasterSecrets, verifySelfTestAuthorization, } from "./self-test-token.js";
|
|
13
20
|
export type { AuthFlowRequest, AuthFlowResponse, AuthFlowSuccessResponse, ConnectionMode, OperationConnection, OperationErrorResponse, OperationRequest, OperationResponse, OperationSuccessResponse, } from "./types.js";
|
|
14
21
|
export { AuthFlowRequestSchema, AuthFlowSuccessResponseSchema, ConnectionModeSchema, ErrorEnvelopeSchema, OperationConnectionSchema, OperationErrorResponseSchema, OperationRequestSchema, OperationSuccessResponseSchema, } from "./types.js";
|
|
22
|
+
export { HttpTelemetryCollector, type HttpTelemetrySink, type HttpTelemetryRequestSink, type HttpAttemptTelemetryEvent, type HttpAttemptSample, type HttpTelemetryErrorCode, type HttpTelemetryRetryPayload, type HttpTelemetryLogPayload, type HttpTelemetryHeaderPayload, } from "../runtime/http-telemetry.js";
|
|
23
|
+
export type { HttpRetrySummary } from "../types.js";
|
|
15
24
|
export { NativeTelemetryCollector, type NativeAttemptSample, type NativeConnectTelemetryEvent, type NativeLifecycleTelemetryEvent, type NativeTelemetryDiagnostics, type NativeTelemetryErrorCode, type NativeTelemetryHeaderPayload, type NativeTelemetryKind, type NativeTelemetryLifecycleKind, type NativeTelemetryLogPayload, type NativeTelemetryOutcome, type NativeTelemetrySink, type NativeTelemetryVendorSkipReason, type NativeVendorSkipTelemetryEvent, } from "../runtime/native-telemetry.js";
|
package/dist/server/index.js
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
export { RequestTelemetry, closedEnum, } from "../runtime/request-telemetry.js";
|
|
2
|
+
export { OcrTelemetryCollector, bindOcrTelemetry, } from "../runtime/ocr-telemetry.js";
|
|
2
3
|
export { ResolverTelemetryCollector, } from "../runtime/resolver-telemetry.js";
|
|
4
|
+
export { StealthTelemetryCollector, } from "../runtime/stealth-telemetry.js";
|
|
5
|
+
export { SttTelemetryCollector, bindSttTelemetry, } from "../runtime/stt-telemetry.js";
|
|
6
|
+
export { BrowserTelemetryCollector, } from "../runtime/browser-telemetry.js";
|
|
3
7
|
export { createServerApp, createServerAppAsync, ERROR_OBSERVABILITY_HEADER, serve, } from "./serve.js";
|
|
4
8
|
export { computeSelfTestPlanDigest, createSelfTestApp, createSelfTestAuthFlowInvoke, createSelfTestInvoke, DEFAULT_SELF_TEST_REQUEST_BUDGET_MS, isSelfTestReadOnlyOperation, PROVIDER_RUNTIME_SELF_TEST_REQUEST_BUDGET_MS_ENV, resolveSelfTestPort, SELF_TEST_AUTH_FLOW_MULTI_TURN_SKIP_REASON, SELF_TEST_AUTH_FLOW_REJECTED_SKIP_REASON, SELF_TEST_HEALTHZ_PATH, SELF_TEST_PATH, SELF_TEST_SCHEMA_VERSION, SelfTestRequestSchema, } from "./self-test.js";
|
|
5
9
|
export { resolveHealthCheckInputDateTokens, } from "./self-test-input-tokens.js";
|
|
6
10
|
export { collectSelfTestSensitiveValues, redactSelfTestText, SELF_TEST_MAX_TEXT_LENGTH, SELF_TEST_REDACTED_PLACEHOLDER, } from "./self-test-redaction.js";
|
|
7
11
|
export { DEFAULT_SELF_TEST_PORT, deriveSelfTestToken, PROVIDER_RUNTIME_SELF_TEST_MASTER_SECRET_ENV, PROVIDER_RUNTIME_SELF_TEST_MASTER_SECRET_PREVIOUS_ENV, PROVIDER_RUNTIME_SELF_TEST_PORT_ENV, resolveSelfTestMasterSecrets, verifySelfTestAuthorization, } from "./self-test-token.js";
|
|
8
12
|
export { AuthFlowRequestSchema, AuthFlowSuccessResponseSchema, ConnectionModeSchema, ErrorEnvelopeSchema, OperationConnectionSchema, OperationErrorResponseSchema, OperationRequestSchema, OperationSuccessResponseSchema, } from "./types.js";
|
|
13
|
+
export { HttpTelemetryCollector, } from "../runtime/http-telemetry.js";
|
|
9
14
|
export { NativeTelemetryCollector, } from "../runtime/native-telemetry.js";
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
/** Published @apifuse/provider-sdk version, read from the package manifest; "unknown" when unreadable. */
|
|
3
|
+
export function resolveSdkVersion() {
|
|
4
|
+
try {
|
|
5
|
+
const packageJsonUrl = new URL("../../package.json", import.meta.url);
|
|
6
|
+
const parsed = JSON.parse(readFileSync(packageJsonUrl, "utf8"));
|
|
7
|
+
if (parsed &&
|
|
8
|
+
typeof parsed === "object" &&
|
|
9
|
+
"version" in parsed &&
|
|
10
|
+
typeof parsed.version === "string") {
|
|
11
|
+
return parsed.version;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
// fall through to unknown
|
|
16
|
+
}
|
|
17
|
+
return "unknown";
|
|
18
|
+
}
|
|
19
|
+
export const SDK_VERSION = resolveSdkVersion();
|