@apifuse/provider-sdk 2.2.0-beta.3 → 2.2.0-beta.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AUTHORING.md +493 -5
- package/CHANGELOG.md +131 -1
- package/README.md +52 -6
- package/SUBMISSION.md +1 -1
- package/bin/apifuse-check.ts +106 -62
- package/bin/apifuse-create.ts +1 -1
- package/bin/apifuse-dev.ts +63 -55
- package/bin/apifuse-pack-check.ts +22 -2
- package/bin/apifuse-pack-smoke.ts +78 -82
- package/bin/apifuse-pack-types.ts +583 -0
- package/bin/apifuse-perf.ts +59 -140
- package/bin/apifuse-record.ts +698 -113
- package/bin/apifuse-submit-check.ts +517 -44
- package/bin/apifuse-sync-assets.ts +117 -0
- package/bin/apifuse.ts +1 -1
- package/bin/submit-check-delimited-text.ts +50 -0
- package/bin/submit-check-xml.ts +1 -1
- package/dist/auth-turn/index.d.ts +4 -4
- package/dist/auth-turn/index.js +1 -1
- package/dist/auth.d.ts +16 -2
- package/dist/auth.js +76 -18
- package/dist/ceremonies/index.d.ts +9 -1
- package/dist/ceremonies/index.js +117 -29
- package/dist/cli/commands.d.ts +1 -1
- package/dist/cli/commands.js +8 -0
- package/dist/cli/create.d.ts +3 -0
- package/dist/cli/create.js +34 -35
- package/dist/cli/prompt-assets.d.ts +80 -0
- package/dist/cli/prompt-assets.js +743 -0
- package/dist/cli/templates/provider/AGENTS.md.tpl +17 -8
- package/dist/cli/templates/provider/README.md.tpl +4 -4
- package/dist/config/loader.d.ts +176 -17
- package/dist/config/loader.js +434 -161
- package/dist/contract-serialization.d.ts +2 -2
- package/dist/contract-serialization.js +7 -14
- package/dist/contract-types.d.ts +3 -2
- package/dist/contract.d.ts +3 -3
- package/dist/contract.js +6 -6
- package/dist/declaration-validation.d.ts +23 -0
- package/dist/declaration-validation.js +159 -0
- package/dist/define.d.ts +13 -1
- package/dist/define.js +391 -122
- package/dist/dev.d.ts +1 -1
- package/dist/dev.js +1 -1
- package/dist/error-resolution.d.ts +4 -0
- package/dist/error-resolution.js +123 -0
- package/dist/errors.d.ts +19 -1
- package/dist/errors.js +41 -3
- package/dist/fixture-sanitization.d.ts +26 -0
- package/dist/fixture-sanitization.js +216 -0
- package/dist/i18n/catalog.d.ts +2 -2
- package/dist/i18n/catalog.js +4 -10
- package/dist/i18n/index.d.ts +2 -2
- package/dist/i18n/index.js +2 -2
- package/dist/i18n/keys.d.ts +2 -2
- package/dist/index.d.ts +50 -42
- package/dist/index.js +41 -37
- package/dist/lint.d.ts +6 -1
- package/dist/lint.js +370 -18
- package/dist/native-address.d.ts +43 -0
- package/dist/native-address.js +281 -0
- package/dist/native-egress-policy.d.ts +31 -0
- package/dist/native-egress-policy.js +288 -0
- package/dist/observability.d.ts +5 -2
- package/dist/observability.js +48 -1
- package/dist/provider.d.ts +13 -11
- package/dist/provider.js +10 -9
- package/dist/public-schema-field-lint.d.ts +1 -1
- package/dist/recipes/gov-api.js +1 -1
- package/dist/runtime/auth-flow.d.ts +3 -1
- package/dist/runtime/auth-flow.js +8 -3
- package/dist/runtime/browser.d.ts +1 -1
- package/dist/runtime/browser.js +138 -40
- package/dist/runtime/cache.d.ts +2 -1
- package/dist/runtime/cache.js +173 -23
- package/dist/runtime/choice-wordlist.d.ts +9 -0
- package/dist/runtime/choice-wordlist.js +138 -0
- package/dist/runtime/choice.d.ts +14 -1
- package/dist/runtime/choice.js +566 -101
- package/dist/runtime/credential.d.ts +1 -1
- package/dist/runtime/credential.js +1 -1
- package/dist/runtime/env.d.ts +1 -1
- package/dist/runtime/executor.d.ts +1 -1
- package/dist/runtime/executor.js +25 -3
- package/dist/runtime/http.d.ts +3 -2
- package/dist/runtime/http.js +517 -55
- package/dist/runtime/insights.d.ts +1 -1
- package/dist/runtime/insights.js +6 -13
- package/dist/runtime/instrumentation.d.ts +2 -2
- package/dist/runtime/instrumentation.js +371 -23
- package/dist/runtime/keyring.js +1 -1
- package/dist/runtime/namespace.js +1 -1
- package/dist/runtime/native-network-errors.d.ts +33 -0
- package/dist/runtime/native-network-errors.js +69 -0
- package/dist/runtime/native-network.d.ts +96 -0
- package/dist/runtime/native-network.js +1232 -0
- package/dist/runtime/ocr.d.ts +29 -0
- package/dist/runtime/ocr.js +440 -0
- package/dist/runtime/otlp.d.ts +1 -1
- package/dist/runtime/perf.d.ts +1 -1
- package/dist/runtime/provider.d.ts +1 -1
- package/dist/runtime/provider.js +1 -2
- package/dist/runtime/proxy-errors.d.ts +1 -1
- package/dist/runtime/proxy-errors.js +9 -7
- package/dist/runtime/proxy-nodemaven.d.ts +56 -0
- package/dist/runtime/proxy-nodemaven.js +146 -0
- package/dist/runtime/proxy-retry-policy.d.ts +2 -2
- package/dist/runtime/proxy-retry-policy.js +2 -2
- package/dist/runtime/proxy-telemetry.d.ts +2 -1
- package/dist/runtime/proxy-telemetry.js +58 -52
- package/dist/runtime/redirects.d.ts +29 -0
- package/dist/runtime/redirects.js +36 -0
- package/dist/runtime/redis.d.ts +1 -1
- package/dist/runtime/redis.js +5 -5
- package/dist/runtime/request-options.d.ts +68 -1
- package/dist/runtime/request-options.js +548 -0
- package/dist/runtime/resolver-config.d.ts +6 -0
- package/dist/runtime/resolver-config.js +6 -0
- package/dist/runtime/resolver-public.d.ts +1 -0
- package/dist/runtime/resolver-public.js +1 -0
- package/dist/runtime/resolver-shared.d.ts +3 -0
- package/dist/runtime/resolver-shared.js +12 -0
- package/dist/runtime/resolver-vendors/bindings.d.ts +48 -0
- package/dist/runtime/resolver-vendors/bindings.js +40 -0
- package/dist/runtime/resolver-vendors/browser.d.ts +20 -0
- package/dist/runtime/resolver-vendors/browser.js +282 -0
- package/dist/runtime/resolver-vendors/hosts.d.ts +2 -0
- package/dist/runtime/resolver-vendors/hosts.js +33 -0
- package/dist/runtime/resolver-vendors/twocaptcha.d.ts +24 -0
- package/dist/runtime/resolver-vendors/twocaptcha.js +368 -0
- package/dist/runtime/resolver-vendors/types.d.ts +83 -0
- package/dist/runtime/resolver-vendors/types.js +69 -0
- package/dist/runtime/resolver.d.ts +59 -0
- package/dist/runtime/resolver.js +705 -0
- package/dist/runtime/secrets.d.ts +27 -0
- package/dist/runtime/secrets.js +51 -0
- package/dist/runtime/state.d.ts +5 -2
- package/dist/runtime/state.js +280 -74
- package/dist/runtime/stealth-cookies.d.ts +20 -0
- package/dist/runtime/stealth-cookies.js +111 -0
- package/dist/runtime/stealth.d.ts +30 -5
- package/dist/runtime/stealth.js +523 -259
- package/dist/runtime/stt.d.ts +1 -1
- package/dist/runtime/stt.js +12 -27
- package/dist/runtime/timeout.d.ts +5 -0
- package/dist/runtime/timeout.js +12 -0
- package/dist/runtime/trace.d.ts +2 -2
- package/dist/runtime/trace.js +2 -4
- package/dist/runtime/waterfall.d.ts +1 -1
- package/dist/schema.d.ts +1 -1
- package/dist/schema.js +7 -15
- package/dist/serve.d.ts +1 -1
- package/dist/serve.js +1 -1
- package/dist/server/index.d.ts +7 -7
- package/dist/server/index.js +6 -6
- package/dist/server/self-test-input-tokens.d.ts +2 -1
- package/dist/server/self-test-input-tokens.js +18 -14
- package/dist/server/self-test-redaction.d.ts +1 -1
- package/dist/server/self-test-redaction.js +1 -1
- package/dist/server/self-test.d.ts +117 -3
- package/dist/server/self-test.js +787 -151
- package/dist/server/serve-implementation.d.ts +210 -0
- package/dist/server/serve-implementation.js +2078 -0
- package/dist/server/serve.d.ts +1 -70
- package/dist/server/serve.js +1 -1143
- package/dist/server/types.d.ts +34 -9
- package/dist/server/types.js +8 -1
- package/dist/stateful/errors.d.ts +19 -0
- package/dist/stateful/errors.js +24 -0
- package/dist/stateful/http-provider-event-emitter.d.ts +40 -0
- package/dist/stateful/http-provider-event-emitter.js +237 -0
- package/dist/stateful/http-session-owner-registry.d.ts +44 -0
- package/dist/stateful/http-session-owner-registry.js +210 -0
- package/dist/stateful/index.d.ts +18 -0
- package/dist/stateful/index.js +18 -0
- package/dist/stateful/provider-event-delivery-failures.d.ts +32 -0
- package/dist/stateful/provider-event-delivery-failures.js +43 -0
- package/dist/stateful/provider-event-pipeline-metrics.d.ts +46 -0
- package/dist/stateful/provider-event-pipeline-metrics.js +48 -0
- package/dist/stateful/provider-event-pipeline.d.ts +50 -0
- package/dist/stateful/provider-event-pipeline.js +1 -0
- package/dist/stateful/provider-events.d.ts +101 -0
- package/dist/stateful/provider-events.js +289 -0
- package/dist/stateful/session-key.d.ts +15 -0
- package/dist/stateful/session-key.js +86 -0
- package/dist/stateful/stateful-provider-adapter-context.d.ts +5 -0
- package/dist/stateful/stateful-provider-adapter-context.js +42 -0
- package/dist/stateful/stateful-provider-adapter-metrics.d.ts +15 -0
- package/dist/stateful/stateful-provider-adapter-metrics.js +21 -0
- package/dist/stateful/stateful-provider-adapter.d.ts +98 -0
- package/dist/stateful/stateful-provider-adapter.js +287 -0
- package/dist/stateful/stateful-provider-observability.d.ts +62 -0
- package/dist/stateful/stateful-provider-observability.js +161 -0
- package/dist/stateful/stateful-provider-owner-forwarder.d.ts +41 -0
- package/dist/stateful/stateful-provider-owner-forwarder.js +215 -0
- package/dist/stateful/stateful-provider-runtime-context.d.ts +32 -0
- package/dist/stateful/stateful-provider-runtime-context.js +60 -0
- package/dist/stateful/stateful-provider-runtime-executor.d.ts +34 -0
- package/dist/stateful/stateful-provider-runtime-executor.js +52 -0
- package/dist/stateful/stateful-provider-session-routing.d.ts +67 -0
- package/dist/stateful/stateful-provider-session-routing.js +345 -0
- package/dist/stateful/stateful-provider-session-runtime.d.ts +98 -0
- package/dist/stateful/stateful-provider-session-runtime.js +245 -0
- package/dist/stateful-signing.d.ts +18 -0
- package/dist/stateful-signing.js +27 -0
- package/dist/stealth/profiles.d.ts +1 -1
- package/dist/stealth/profiles.js +21 -21
- package/dist/stream-evidence.d.ts +74 -0
- package/dist/stream-evidence.js +785 -0
- package/dist/stream.d.ts +1 -1
- package/dist/stream.js +7 -1
- package/dist/testing/index.d.ts +3 -2
- package/dist/testing/index.js +3 -2
- package/dist/testing/run.d.ts +32 -2
- package/dist/testing/run.js +488 -28
- package/dist/types.d.ts +566 -19
- package/dist/types.js +1 -0
- package/dist/user-input.d.ts +30 -0
- package/dist/user-input.js +66 -0
- package/package.json +42 -7
- package/src/auth-turn/index.ts +2 -2
- package/src/auth.ts +146 -86
- package/src/ceremonies/index.ts +167 -92
- package/src/cli/commands.ts +10 -0
- package/src/cli/create.ts +42 -35
- package/src/cli/prompt-assets.ts +865 -0
- package/src/cli/templates/provider/AGENTS.md.tpl +17 -8
- package/src/cli/templates/provider/README.md.tpl +4 -4
- package/src/config/loader.ts +667 -289
- package/src/contract-serialization.ts +10 -18
- package/src/contract-types.ts +3 -2
- package/src/contract.ts +14 -28
- package/src/declaration-validation.ts +202 -0
- package/src/define.ts +631 -495
- package/src/dev.ts +4 -9
- package/src/error-resolution.ts +128 -0
- package/src/errors.ts +56 -11
- package/src/fixture-sanitization.ts +247 -0
- package/src/i18n/catalog.ts +10 -32
- package/src/i18n/index.ts +2 -2
- package/src/i18n/keys.ts +5 -11
- package/src/index.ts +158 -44
- package/src/lint.ts +488 -154
- package/src/native-address.ts +340 -0
- package/src/native-egress-policy.ts +358 -0
- package/src/observability.ts +51 -1
- package/src/provider.ts +66 -11
- package/src/public-schema-field-lint.ts +7 -33
- package/src/recipes/gov-api.ts +2 -5
- package/src/runtime/auth-flow.ts +13 -7
- package/src/runtime/browser.ts +252 -207
- package/src/runtime/cache.ts +209 -81
- package/src/runtime/choice-wordlist.ts +145 -0
- package/src/runtime/choice.ts +758 -197
- package/src/runtime/credential.ts +2 -2
- package/src/runtime/env.ts +1 -1
- package/src/runtime/executor.ts +37 -19
- package/src/runtime/http.ts +645 -65
- package/src/runtime/insights.ts +15 -53
- package/src/runtime/instrumentation.ts +530 -67
- package/src/runtime/keyring.ts +7 -19
- package/src/runtime/namespace.ts +2 -7
- package/src/runtime/native-network-errors.ts +99 -0
- package/src/runtime/native-network.ts +1605 -0
- package/src/runtime/ocr.ts +523 -0
- package/src/runtime/otlp.ts +12 -23
- package/src/runtime/perf.ts +1 -1
- package/src/runtime/provider.ts +4 -9
- package/src/runtime/proxy-errors.ts +29 -42
- package/src/runtime/proxy-nodemaven.ts +221 -0
- package/src/runtime/proxy-retry-policy.ts +3 -3
- package/src/runtime/proxy-telemetry.ts +84 -77
- package/src/runtime/redirects.ts +66 -0
- package/src/runtime/redis.ts +10 -13
- package/src/runtime/request-options.ts +679 -9
- package/src/runtime/resolver-config.ts +6 -0
- package/src/runtime/resolver-public.ts +18 -0
- package/src/runtime/resolver-shared.ts +17 -0
- package/src/runtime/resolver-vendors/bindings.ts +56 -0
- package/src/runtime/resolver-vendors/browser.ts +408 -0
- package/src/runtime/resolver-vendors/hosts.ts +38 -0
- package/src/runtime/resolver-vendors/twocaptcha.ts +500 -0
- package/src/runtime/resolver-vendors/types.ts +173 -0
- package/src/runtime/resolver.ts +1060 -0
- package/src/runtime/secrets.ts +64 -0
- package/src/runtime/state.ts +399 -161
- package/src/runtime/stealth-cookies.ts +132 -0
- package/src/runtime/stealth.ts +681 -295
- package/src/runtime/stt.ts +39 -113
- package/src/runtime/timeout.ts +18 -0
- package/src/runtime/trace.ts +14 -44
- package/src/runtime/waterfall.ts +5 -18
- package/src/schema.ts +23 -84
- package/src/serve.ts +6 -1
- package/src/server/index.ts +30 -7
- package/src/server/self-test-input-tokens.ts +29 -14
- package/src/server/self-test-redaction.ts +2 -2
- package/src/server/self-test.ts +1030 -180
- package/src/server/serve-implementation.ts +3062 -0
- package/src/server/serve.ts +1 -1781
- package/src/server/types.ts +12 -13
- package/src/stateful/README.md +146 -0
- package/src/stateful/errors.ts +35 -0
- package/src/stateful/http-provider-event-emitter.ts +314 -0
- package/src/stateful/http-session-owner-registry.ts +306 -0
- package/src/stateful/index.ts +18 -0
- package/src/stateful/provider-event-delivery-failures.ts +80 -0
- package/src/stateful/provider-event-pipeline-metrics.ts +95 -0
- package/src/stateful/provider-event-pipeline.ts +61 -0
- package/src/stateful/provider-events.ts +462 -0
- package/src/stateful/session-key.ts +111 -0
- package/src/stateful/stateful-provider-adapter-context.ts +59 -0
- package/src/stateful/stateful-provider-adapter-metrics.ts +48 -0
- package/src/stateful/stateful-provider-adapter.ts +562 -0
- package/src/stateful/stateful-provider-observability.ts +261 -0
- package/src/stateful/stateful-provider-owner-forwarder.ts +287 -0
- package/src/stateful/stateful-provider-runtime-context.ts +92 -0
- package/src/stateful/stateful-provider-runtime-executor.ts +96 -0
- package/src/stateful/stateful-provider-session-routing.ts +546 -0
- package/src/stateful/stateful-provider-session-runtime.ts +403 -0
- package/src/stateful-signing.ts +46 -0
- package/src/stealth/profiles.ts +27 -33
- package/src/stream-evidence.ts +988 -0
- package/src/stream.ts +16 -20
- package/src/testing/index.ts +11 -2
- package/src/testing/run.ts +668 -74
- package/src/types.ts +665 -35
- package/src/user-input.ts +118 -0
- package/dist/cli/templates/provider/CLAUDE.md.tpl +0 -1
- package/src/cli/templates/provider/CLAUDE.md.tpl +0 -1
- /package/dist/cli/templates/provider/{skills → .agents/skills}/fixtures-and-recording/SKILL.md.tpl +0 -0
- /package/dist/cli/templates/provider/{skills → .agents/skills}/health-checks-and-fail-closed/SKILL.md.tpl +0 -0
- /package/dist/cli/templates/provider/{skills → .agents/skills}/normalization-standards/SKILL.md.tpl +0 -0
- /package/dist/cli/templates/provider/{skills → .agents/skills}/pagination-and-counts/SKILL.md.tpl +0 -0
- /package/dist/cli/templates/provider/{skills → .agents/skills}/upstream-contract-verification/SKILL.md.tpl +0 -0
- /package/dist/cli/templates/provider/{skills → .agents/skills}/upstream-notes/README.md.tpl +0 -0
- /package/src/cli/templates/provider/{skills → .agents/skills}/fixtures-and-recording/SKILL.md.tpl +0 -0
- /package/src/cli/templates/provider/{skills → .agents/skills}/health-checks-and-fail-closed/SKILL.md.tpl +0 -0
- /package/src/cli/templates/provider/{skills → .agents/skills}/normalization-standards/SKILL.md.tpl +0 -0
- /package/src/cli/templates/provider/{skills → .agents/skills}/pagination-and-counts/SKILL.md.tpl +0 -0
- /package/src/cli/templates/provider/{skills → .agents/skills}/upstream-contract-verification/SKILL.md.tpl +0 -0
- /package/src/cli/templates/provider/{skills → .agents/skills}/upstream-notes/README.md.tpl +0 -0
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
isRecord,
|
|
7
7
|
type JsonValue,
|
|
8
8
|
toJsonValue,
|
|
9
|
-
} from "./contract-json";
|
|
10
|
-
import type { SchemaLike } from "./types";
|
|
9
|
+
} from "./contract-json.js";
|
|
10
|
+
import type { SchemaLike } from "./types.js";
|
|
11
11
|
|
|
12
12
|
export function describeSchema(schema: SchemaLike): JsonValue {
|
|
13
13
|
if (isZodSchema(schema)) {
|
|
@@ -17,10 +17,7 @@ export function describeSchema(schema: SchemaLike): JsonValue {
|
|
|
17
17
|
vendor: "zod",
|
|
18
18
|
typeName: getSchemaTypeName(schema),
|
|
19
19
|
jsonSchema,
|
|
20
|
-
jsonSchemaHash:
|
|
21
|
-
jsonSchema === undefined
|
|
22
|
-
? undefined
|
|
23
|
-
: digest(canonicalJson(jsonSchema)),
|
|
20
|
+
jsonSchemaHash: jsonSchema === undefined ? undefined : digest(canonicalJson(jsonSchema)),
|
|
24
21
|
});
|
|
25
22
|
}
|
|
26
23
|
const standard = isRecord(schema) ? schema["~standard"] : undefined;
|
|
@@ -30,8 +27,7 @@ export function describeSchema(schema: SchemaLike): JsonValue {
|
|
|
30
27
|
standard: "standard-schema-v1",
|
|
31
28
|
vendor: typeof standard.vendor === "string" ? standard.vendor : "unknown",
|
|
32
29
|
version:
|
|
33
|
-
typeof standard.version === "number" ||
|
|
34
|
-
typeof standard.version === "string"
|
|
30
|
+
typeof standard.version === "number" || typeof standard.version === "string"
|
|
35
31
|
? standard.version
|
|
36
32
|
: undefined,
|
|
37
33
|
});
|
|
@@ -43,9 +39,7 @@ export function describeSchema(schema: SchemaLike): JsonValue {
|
|
|
43
39
|
});
|
|
44
40
|
}
|
|
45
41
|
|
|
46
|
-
export function serializeSmsMatcher(
|
|
47
|
-
value: Record<string, unknown>,
|
|
48
|
-
): Record<string, unknown> {
|
|
42
|
+
export function serializeSmsMatcher(value: Record<string, unknown>): Record<string, unknown> {
|
|
49
43
|
const code = value.code;
|
|
50
44
|
if (!isRecord(code)) return value;
|
|
51
45
|
const pattern = code.pattern;
|
|
@@ -70,14 +64,12 @@ function isZodSchema(schema: SchemaLike): schema is ZodType {
|
|
|
70
64
|
return schema instanceof z.ZodType;
|
|
71
65
|
}
|
|
72
66
|
|
|
73
|
-
function zodJsonSchema(schema: ZodType): JsonValue
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
} catch (error) {
|
|
78
|
-
if (error instanceof Error) return undefined;
|
|
79
|
-
throw error;
|
|
67
|
+
function zodJsonSchema(schema: ZodType): JsonValue {
|
|
68
|
+
const jsonSchema = toJsonValue(z.toJSONSchema(schema));
|
|
69
|
+
if (jsonSchema === undefined) {
|
|
70
|
+
throw new TypeError("z.toJSONSchema() returned a non-JSON value");
|
|
80
71
|
}
|
|
72
|
+
return jsonSchema;
|
|
81
73
|
}
|
|
82
74
|
|
|
83
75
|
function getSchemaTypeName(schema: SchemaLike): string | undefined {
|
package/src/contract-types.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { JsonValue } from "./contract-json";
|
|
2
|
-
import type { ProviderDefinition } from "./types";
|
|
1
|
+
import type { JsonValue } from "./contract-json.js";
|
|
2
|
+
import type { ProviderDefinition } from "./types.js";
|
|
3
3
|
|
|
4
4
|
export const PROVIDER_CONTRACT_SCHEMA_VERSION = "2026-06-23";
|
|
5
5
|
|
|
@@ -13,6 +13,7 @@ export interface ProviderContractSnapshot {
|
|
|
13
13
|
readonly allowedHosts?: readonly string[];
|
|
14
14
|
readonly stealth?: JsonValue;
|
|
15
15
|
readonly proxy?: JsonValue;
|
|
16
|
+
readonly ocr?: JsonValue;
|
|
16
17
|
readonly stt?: JsonValue;
|
|
17
18
|
readonly browser?: JsonValue;
|
|
18
19
|
readonly auth?: JsonValue;
|
package/src/contract.ts
CHANGED
|
@@ -6,13 +6,13 @@ import {
|
|
|
6
6
|
type JsonPrimitive,
|
|
7
7
|
type JsonValue,
|
|
8
8
|
toJsonValue,
|
|
9
|
-
} from "./contract-json";
|
|
10
|
-
import { describeSchema, serializeSmsMatcher } from "./contract-serialization";
|
|
9
|
+
} from "./contract-json.js";
|
|
10
|
+
import { describeSchema, serializeSmsMatcher } from "./contract-serialization.js";
|
|
11
11
|
import {
|
|
12
12
|
PROVIDER_CONTRACT_SCHEMA_VERSION,
|
|
13
13
|
type ProviderContractOperation,
|
|
14
14
|
type ProviderContractSnapshot,
|
|
15
|
-
} from "./contract-types";
|
|
15
|
+
} from "./contract-types.js";
|
|
16
16
|
import type {
|
|
17
17
|
HealthCheckSuite,
|
|
18
18
|
HealthCheckUnsupported,
|
|
@@ -20,7 +20,7 @@ import type {
|
|
|
20
20
|
OperationDefinition,
|
|
21
21
|
OperationTransport,
|
|
22
22
|
ProviderDefinition,
|
|
23
|
-
} from "./types";
|
|
23
|
+
} from "./types.js";
|
|
24
24
|
|
|
25
25
|
export {
|
|
26
26
|
canonicalJson,
|
|
@@ -31,12 +31,11 @@ export {
|
|
|
31
31
|
type ProviderContractSnapshot,
|
|
32
32
|
};
|
|
33
33
|
|
|
34
|
-
export function extractProviderContract(
|
|
35
|
-
provider: ProviderDefinition,
|
|
36
|
-
): ProviderContractSnapshot {
|
|
34
|
+
export function extractProviderContract(provider: ProviderDefinition): ProviderContractSnapshot {
|
|
37
35
|
const auth = extractAuth(provider.auth);
|
|
38
36
|
const stealth = toJsonValue(provider.stealth);
|
|
39
37
|
const proxy = toJsonValue(provider.proxy);
|
|
38
|
+
const ocr = toJsonValue(provider.ocr);
|
|
40
39
|
const stt = toJsonValue(provider.stt);
|
|
41
40
|
const browser = toJsonValue(provider.browser);
|
|
42
41
|
const reviewed = toJsonValue(provider.reviewed);
|
|
@@ -57,14 +56,11 @@ export function extractProviderContract(
|
|
|
57
56
|
meta: toJsonValue(provider.meta) ?? null,
|
|
58
57
|
operations: Object.entries(provider.operations)
|
|
59
58
|
.sort(([leftId], [rightId]) => leftId.localeCompare(rightId))
|
|
60
|
-
.map(([operationId, operation]) =>
|
|
61
|
-
|
|
62
|
-
),
|
|
63
|
-
...(provider.allowedHosts
|
|
64
|
-
? { allowedHosts: [...provider.allowedHosts].sort() }
|
|
65
|
-
: {}),
|
|
59
|
+
.map(([operationId, operation]) => extractOperation(operationId, operation)),
|
|
60
|
+
...(provider.allowedHosts ? { allowedHosts: [...provider.allowedHosts].sort() } : {}),
|
|
66
61
|
...(stealth === undefined ? {} : { stealth }),
|
|
67
62
|
...(proxy === undefined ? {} : { proxy }),
|
|
63
|
+
...(ocr === undefined ? {} : { ocr }),
|
|
68
64
|
...(stt === undefined ? {} : { stt }),
|
|
69
65
|
...(browser === undefined ? {} : { browser }),
|
|
70
66
|
...(auth === undefined ? {} : { auth }),
|
|
@@ -78,9 +74,7 @@ export function extractProviderContract(
|
|
|
78
74
|
};
|
|
79
75
|
}
|
|
80
76
|
|
|
81
|
-
export function digestProviderContract(
|
|
82
|
-
snapshot: ProviderContractSnapshot,
|
|
83
|
-
): string {
|
|
77
|
+
export function digestProviderContract(snapshot: ProviderContractSnapshot): string {
|
|
84
78
|
return createHash("sha256").update(canonicalJson(snapshot)).digest("hex");
|
|
85
79
|
}
|
|
86
80
|
|
|
@@ -105,9 +99,7 @@ function extractOperation(
|
|
|
105
99
|
const upstream = toJsonValue(operation.upstream);
|
|
106
100
|
const hints = toJsonValue(operation.hints);
|
|
107
101
|
const healthCheck = extractHealthCheck(operation.healthCheck);
|
|
108
|
-
const healthCheckUnsupported = extractHealthCheckUnsupported(
|
|
109
|
-
operation.healthCheckUnsupported,
|
|
110
|
-
);
|
|
102
|
+
const healthCheckUnsupported = extractHealthCheckUnsupported(operation.healthCheckUnsupported);
|
|
111
103
|
|
|
112
104
|
return {
|
|
113
105
|
id: operationId,
|
|
@@ -149,9 +141,7 @@ function extractAuth(value: ProviderDefinition["auth"]): JsonValue | undefined {
|
|
|
149
141
|
});
|
|
150
142
|
}
|
|
151
143
|
|
|
152
|
-
function extractTransport(
|
|
153
|
-
value: OperationTransport | undefined,
|
|
154
|
-
): JsonValue | undefined {
|
|
144
|
+
function extractTransport(value: OperationTransport | undefined): JsonValue | undefined {
|
|
155
145
|
if (!value) return undefined;
|
|
156
146
|
if (value.kind !== "sse") return toJsonValue(value);
|
|
157
147
|
return compactObject({
|
|
@@ -164,9 +154,7 @@ function extractTransport(
|
|
|
164
154
|
});
|
|
165
155
|
}
|
|
166
156
|
|
|
167
|
-
function extractHealthCheck(
|
|
168
|
-
value: HealthCheckSuite | undefined,
|
|
169
|
-
): JsonValue | undefined {
|
|
157
|
+
function extractHealthCheck(value: HealthCheckSuite | undefined): JsonValue | undefined {
|
|
170
158
|
if (!value) return undefined;
|
|
171
159
|
return compactObject({
|
|
172
160
|
interval: value.interval,
|
|
@@ -204,9 +192,7 @@ function extractHealthJourney(value: HealthJourneyDefinition): JsonValue {
|
|
|
204
192
|
cooldown: value.cooldown,
|
|
205
193
|
smsMatchers: toJsonValue(
|
|
206
194
|
value.smsMatchers?.map((matcher) =>
|
|
207
|
-
serializeSmsMatcher(
|
|
208
|
-
copyRecordWithout(matcher, new Set(["extractOtp"])),
|
|
209
|
-
),
|
|
195
|
+
serializeSmsMatcher(copyRecordWithout(matcher, new Set(["extractOtp"]))),
|
|
210
196
|
),
|
|
211
197
|
),
|
|
212
198
|
requiredSecrets: toJsonValue(value.requiredSecrets),
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { describeSchema } from "./contract-serialization.js";
|
|
2
|
+
import { ProviderError } from "./errors.js";
|
|
3
|
+
import type {
|
|
4
|
+
HealthJourneyDefinition,
|
|
5
|
+
ProviderDefinition,
|
|
6
|
+
ProviderProxyPolicy,
|
|
7
|
+
ProviderProxyProvider,
|
|
8
|
+
} from "./types.js";
|
|
9
|
+
|
|
10
|
+
export const DECLARATION_INVALID_CODE = "DECLARATION_INVALID";
|
|
11
|
+
|
|
12
|
+
export const DECLARATION_RULE_IDS = {
|
|
13
|
+
challengeShape: "credentials-challenge-shape",
|
|
14
|
+
journeyExecutable: "health-journey-executable",
|
|
15
|
+
schemaSerializable: "operation-schema-serializable",
|
|
16
|
+
proxyExplicitPolicy: "proxy-explicit-policy",
|
|
17
|
+
proxyVendorExclusive: "proxy-vendor-fields-exclusive",
|
|
18
|
+
proxyNoMixedVendors: "proxy-no-mixed-vendors",
|
|
19
|
+
proxySmartproxyGeo: "proxy-smartproxy-country-only",
|
|
20
|
+
operationUpstreamProxy: "operation-upstream-proxy-unsupported",
|
|
21
|
+
} as const;
|
|
22
|
+
|
|
23
|
+
export type DeclarationRuleId =
|
|
24
|
+
(typeof DECLARATION_RULE_IDS)[keyof typeof DECLARATION_RULE_IDS];
|
|
25
|
+
|
|
26
|
+
export type DeclarationViolation = {
|
|
27
|
+
ruleId: DeclarationRuleId;
|
|
28
|
+
path: string;
|
|
29
|
+
message: string;
|
|
30
|
+
fix: string;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export function declarationInvalidError(
|
|
34
|
+
violations: readonly DeclarationViolation[],
|
|
35
|
+
): ProviderError {
|
|
36
|
+
const summary = violations
|
|
37
|
+
.map((violation) => `${violation.path} [${violation.ruleId}]: ${violation.message}`)
|
|
38
|
+
.join("\n");
|
|
39
|
+
return new ProviderError(
|
|
40
|
+
`Provider declaration is invalid (${violations.length} violation${violations.length === 1 ? "" : "s"}).${summary ? `\n${summary}` : ""}`,
|
|
41
|
+
{
|
|
42
|
+
code: DECLARATION_INVALID_CODE,
|
|
43
|
+
details: { violations: [...violations] },
|
|
44
|
+
fix: "Apply every violation's fix hint, then validate the declaration again.",
|
|
45
|
+
},
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Enforces declaration rules whose runtime behavior would otherwise fail open. */
|
|
50
|
+
export function validateFailClosedDeclaration(provider: ProviderDefinition): void {
|
|
51
|
+
const violations: DeclarationViolation[] = [];
|
|
52
|
+
validateHealthDeclaration(provider, violations);
|
|
53
|
+
validateSchemaDeclaration(provider, violations);
|
|
54
|
+
validateProxyDeclaration(provider, violations);
|
|
55
|
+
validateOperationDeclaration(provider, violations);
|
|
56
|
+
if (violations.length > 0) throw declarationInvalidError(violations);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function validateHealthDeclaration(
|
|
60
|
+
provider: ProviderDefinition,
|
|
61
|
+
violations: DeclarationViolation[],
|
|
62
|
+
): void {
|
|
63
|
+
for (const [index, journey] of (provider.healthJourneys ?? []).entries()) {
|
|
64
|
+
if (!journey || typeof journey !== "object") continue;
|
|
65
|
+
if (typeof journey.run !== "function") {
|
|
66
|
+
const journeyPath = healthJourneyPath(journey, index);
|
|
67
|
+
violations.push({
|
|
68
|
+
ruleId: DECLARATION_RULE_IDS.journeyExecutable,
|
|
69
|
+
path: `${journeyPath}.run`,
|
|
70
|
+
message: "coversOperations cannot provide health coverage without executable run logic.",
|
|
71
|
+
fix: `Add an async run(ctx) implementation to ${journeyPath}.`,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// NOTE: healthCheck.cases[].enabled is intentionally NOT validated here.
|
|
77
|
+
// self-test.ts reports a gated case as status "skipped" with skipReason
|
|
78
|
+
// "disabled", so the skip is visible in results rather than silent — it is a
|
|
79
|
+
// supported conditional-execution feature, not a class-1 silent no-op.
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function healthJourneyPath(journey: HealthJourneyDefinition, index: number): string {
|
|
83
|
+
return typeof journey.id === "string" && journey.id.length > 0
|
|
84
|
+
? `healthJourneys.${journey.id}`
|
|
85
|
+
: `healthJourneys[${index}]`;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function validateSchemaDeclaration(
|
|
89
|
+
provider: ProviderDefinition,
|
|
90
|
+
violations: DeclarationViolation[],
|
|
91
|
+
): void {
|
|
92
|
+
for (const [operationId, operation] of Object.entries(provider.operations ?? {})) {
|
|
93
|
+
const schemaEntries: Array<[string, unknown]> = [
|
|
94
|
+
[`operations.${operationId}.input`, operation.input],
|
|
95
|
+
[`operations.${operationId}.output`, operation.output],
|
|
96
|
+
];
|
|
97
|
+
// SSE event schemas reach contract extraction the same way input/output do,
|
|
98
|
+
// so a transform-bearing event schema would abort extraction at runtime while
|
|
99
|
+
// passing declaration checks. Validate them under the same rule.
|
|
100
|
+
const transport = operation.transport;
|
|
101
|
+
if (transport?.kind === "sse") {
|
|
102
|
+
for (const [eventName, eventSchema] of Object.entries(transport.events ?? {})) {
|
|
103
|
+
schemaEntries.push([
|
|
104
|
+
`operations.${operationId}.transport.events.${eventName}`,
|
|
105
|
+
eventSchema,
|
|
106
|
+
]);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
for (const [path, schema] of schemaEntries) {
|
|
110
|
+
try {
|
|
111
|
+
describeSchema(schema as Parameters<typeof describeSchema>[0]);
|
|
112
|
+
} catch (error) {
|
|
113
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
114
|
+
violations.push({
|
|
115
|
+
ruleId: DECLARATION_RULE_IDS.schemaSerializable,
|
|
116
|
+
path,
|
|
117
|
+
message: `schema conversion to JSON Schema failed: ${reason}`,
|
|
118
|
+
fix: `Replace unsupported constructs in ${path} so z.toJSONSchema() succeeds.`,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const MANAGED_PROXY_VENDORS = new Set<ProviderProxyProvider>(["smartproxy", "nodemaven"]);
|
|
126
|
+
const STATIC_PROXY_VENDORS = new Set<ProviderProxyProvider>(["custom", "decodo"]);
|
|
127
|
+
|
|
128
|
+
function validateProxyDeclaration(
|
|
129
|
+
provider: ProviderDefinition,
|
|
130
|
+
violations: DeclarationViolation[],
|
|
131
|
+
): void {
|
|
132
|
+
if (provider.proxy === true) {
|
|
133
|
+
violations.push({
|
|
134
|
+
ruleId: DECLARATION_RULE_IDS.proxyExplicitPolicy,
|
|
135
|
+
path: "proxy",
|
|
136
|
+
message: "proxy: true does not require resolvable proxy egress.",
|
|
137
|
+
fix: 'Replace proxy: true with an explicit policy such as proxy: { mode: "required", providers: ["smartproxy"] }.',
|
|
138
|
+
});
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (!provider.proxy || typeof provider.proxy !== "object") return;
|
|
142
|
+
|
|
143
|
+
const policy = provider.proxy as ProviderProxyPolicy;
|
|
144
|
+
const hasProvider = policy.provider !== undefined;
|
|
145
|
+
const hasProviders = policy.providers !== undefined;
|
|
146
|
+
if (hasProvider && hasProviders) {
|
|
147
|
+
violations.push({
|
|
148
|
+
ruleId: DECLARATION_RULE_IDS.proxyVendorExclusive,
|
|
149
|
+
path: "proxy",
|
|
150
|
+
message: "provider and providers are ambiguous when declared together.",
|
|
151
|
+
fix: "Keep either proxy.provider or proxy.providers, and remove the other field.",
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const vendors = declaredProxyVendors(policy);
|
|
156
|
+
if (
|
|
157
|
+
vendors.some((vendor) => MANAGED_PROXY_VENDORS.has(vendor)) &&
|
|
158
|
+
vendors.some((vendor) => STATIC_PROXY_VENDORS.has(vendor))
|
|
159
|
+
) {
|
|
160
|
+
violations.push({
|
|
161
|
+
ruleId: DECLARATION_RULE_IDS.proxyNoMixedVendors,
|
|
162
|
+
path: hasProviders ? "proxy.providers" : "proxy.provider",
|
|
163
|
+
message: "managed and deprecated static proxy vendors cannot share a chain.",
|
|
164
|
+
fix: "Use only smartproxy/nodemaven vendors, or only deprecated static markers, in one policy.",
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (vendors.includes("smartproxy")) {
|
|
169
|
+
for (const field of ["subdivision", "city"] as const) {
|
|
170
|
+
if (policy.geo?.[field] === undefined) continue;
|
|
171
|
+
const path = `proxy.geo.${field}`;
|
|
172
|
+
violations.push({
|
|
173
|
+
ruleId: DECLARATION_RULE_IDS.proxySmartproxyGeo,
|
|
174
|
+
path,
|
|
175
|
+
message: `smartproxy cannot honor ${field}-level geo targeting.`,
|
|
176
|
+
fix: `Remove ${path} or use a vendor chain that can honor it.`,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function declaredProxyVendors(policy: ProviderProxyPolicy): ProviderProxyProvider[] {
|
|
183
|
+
const vendors = [...(policy.providers ?? [])];
|
|
184
|
+
if (policy.provider !== undefined) vendors.push(policy.provider);
|
|
185
|
+
return vendors;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function validateOperationDeclaration(
|
|
189
|
+
provider: ProviderDefinition,
|
|
190
|
+
violations: DeclarationViolation[],
|
|
191
|
+
): void {
|
|
192
|
+
for (const [operationId, operation] of Object.entries(provider.operations ?? {})) {
|
|
193
|
+
if (!operation.upstream?.proxy) continue;
|
|
194
|
+
const path = `operations.${operationId}.upstream.proxy`;
|
|
195
|
+
violations.push({
|
|
196
|
+
ruleId: DECLARATION_RULE_IDS.operationUpstreamProxy,
|
|
197
|
+
path,
|
|
198
|
+
message: "operation-level proxy policy is not wired into operation execution.",
|
|
199
|
+
fix: `Remove ${path} and declare the effective policy at provider.proxy.`,
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
}
|