@apifuse/provider-sdk 2.2.0-beta.5 → 2.2.0-beta.51
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 +537 -33
- package/CHANGELOG.md +205 -1
- package/README.md +83 -22
- package/SUBMISSION.md +2 -2
- package/bin/apifuse-check.ts +165 -11
- package/bin/apifuse-dev.ts +57 -13
- package/bin/apifuse-migrate-operation-declaration.ts +55 -0
- package/bin/apifuse-migrate-shape.ts +202 -0
- package/bin/apifuse-pack-check.ts +22 -2
- package/bin/apifuse-pack-smoke.ts +57 -2
- package/bin/apifuse-pack-types.ts +357 -38
- package/bin/apifuse-perf.ts +14 -13
- package/bin/apifuse-record.ts +709 -72
- package/bin/apifuse-submit-check.ts +2344 -324
- package/bin/apifuse-sync-assets.ts +117 -0
- package/bin/submit-check-delimited-text.ts +50 -0
- package/dist/auth-turn/index.d.ts +3 -3
- package/dist/auth-turn/index.js +1 -1
- package/dist/auth.d.ts +14 -0
- package/dist/auth.js +67 -0
- package/dist/ceremonies/index.d.ts +16 -0
- package/dist/ceremonies/index.js +141 -36
- package/dist/cli/commands.d.ts +1 -1
- package/dist/cli/commands.js +27 -0
- package/dist/cli/create.d.ts +4 -1
- package/dist/cli/create.js +42 -37
- package/dist/cli/migrate-operation-declaration.d.ts +59 -0
- package/dist/cli/migrate-operation-declaration.js +1249 -0
- package/dist/cli/migrate-operation-shape.d.ts +44 -0
- package/dist/cli/migrate-operation-shape.js +113 -0
- package/dist/cli/migrate-provider-shape.d.ts +52 -0
- package/dist/cli/migrate-provider-shape.js +578 -0
- 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/Dockerfile.tpl +1 -1
- package/dist/cli/templates/provider/README.md.tpl +5 -5
- package/dist/cli/templates/provider/index.ts.tpl +6 -3
- package/dist/cli/templates/provider/operations/ping.ts.tpl +4 -1
- package/dist/cli/templates/provider/provider.json.tpl +6 -0
- package/dist/config/loader.d.ts +179 -16
- package/dist/config/loader.js +435 -127
- package/dist/contract-serialization.js +4 -8
- package/dist/contract-types.d.ts +12 -5
- package/dist/contract.js +24 -10
- package/dist/declaration-validation.d.ts +33 -0
- package/dist/declaration-validation.js +266 -0
- package/dist/define.d.ts +66 -29
- package/dist/define.js +778 -69
- package/dist/dev.d.ts +3 -0
- package/dist/dev.js +1 -1
- package/dist/engine.d.ts +78 -0
- package/dist/engine.js +133 -0
- package/dist/error-observability.d.ts +7 -0
- package/dist/error-observability.js +61 -0
- package/dist/error-resolution.d.ts +4 -0
- package/dist/error-resolution.js +122 -0
- package/dist/errors.d.ts +33 -0
- package/dist/errors.js +40 -0
- package/dist/fixture-sanitization.d.ts +28 -0
- package/dist/fixture-sanitization.js +227 -0
- package/dist/health-scenario.d.ts +1842 -0
- package/dist/health-scenario.js +624 -0
- package/dist/index.d.ts +21 -10
- package/dist/index.js +12 -7
- package/dist/lint.d.ts +23 -11
- package/dist/lint.js +572 -69
- 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 +10 -2
- package/dist/provider.js +4 -1
- package/dist/runtime/auth-flow.d.ts +5 -1
- package/dist/runtime/auth-flow.js +6 -0
- package/dist/runtime/browser.d.ts +1 -0
- package/dist/runtime/browser.js +492 -49
- package/dist/runtime/cache.d.ts +1 -0
- package/dist/runtime/cache.js +169 -15
- package/dist/runtime/choice-wordlist.d.ts +9 -0
- package/dist/runtime/choice-wordlist.js +138 -0
- package/dist/runtime/choice.d.ts +13 -1
- package/dist/runtime/choice.js +490 -102
- package/dist/runtime/chrome149-header-order.d.ts +58 -0
- package/dist/runtime/chrome149-header-order.js +289 -0
- package/dist/runtime/env.js +12 -0
- package/dist/runtime/executor.d.ts +3 -2
- package/dist/runtime/executor.js +26 -25
- package/dist/runtime/http.d.ts +1 -0
- package/dist/runtime/http.js +515 -53
- package/dist/runtime/insights.js +2 -2
- package/dist/runtime/instrumentation.d.ts +2 -2
- package/dist/runtime/instrumentation.js +366 -8
- 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 +71 -2
- package/dist/runtime/otlp.js +397 -16
- package/dist/runtime/proxy-errors.js +6 -2
- package/dist/runtime/proxy-nodemaven.d.ts +56 -0
- package/dist/runtime/proxy-nodemaven.js +146 -0
- package/dist/runtime/proxy-telemetry.d.ts +80 -1
- package/dist/runtime/proxy-telemetry.js +154 -47
- 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 +4 -2
- 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 +14 -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 +22 -0
- package/dist/runtime/resolver-vendors/browser.js +377 -0
- package/dist/runtime/resolver-vendors/capsolver.d.ts +22 -0
- package/dist/runtime/resolver-vendors/capsolver.js +531 -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 +408 -0
- package/dist/runtime/resolver-vendors/types.d.ts +94 -0
- package/dist/runtime/resolver-vendors/types.js +96 -0
- package/dist/runtime/resolver.d.ts +72 -0
- package/dist/runtime/resolver.js +771 -0
- package/dist/runtime/secrets.d.ts +27 -0
- package/dist/runtime/secrets.js +51 -0
- package/dist/runtime/state.d.ts +3 -0
- package/dist/runtime/state.js +277 -71
- package/dist/runtime/stealth-cookies.d.ts +20 -0
- package/dist/runtime/stealth-cookies.js +111 -0
- package/dist/runtime/stealth.d.ts +41 -5
- package/dist/runtime/stealth.js +997 -291
- package/dist/runtime/stt.js +1 -12
- package/dist/runtime/timeout.d.ts +5 -0
- package/dist/runtime/timeout.js +12 -0
- package/dist/runtime/trace-config.d.ts +12 -0
- package/dist/runtime/trace-config.js +62 -0
- package/dist/runtime/trace.d.ts +5 -0
- package/dist/runtime/trace.js +43 -10
- package/dist/serve.d.ts +1 -1
- package/dist/serve.js +1 -1
- package/dist/server/error-observability.d.ts +1 -0
- package/dist/server/error-observability.js +1 -0
- package/dist/server/index.d.ts +5 -2
- package/dist/server/index.js +2 -2
- 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.d.ts +14 -3
- package/dist/server/self-test.js +129 -58
- package/dist/server/serve-implementation.d.ts +230 -0
- package/dist/server/serve-implementation.js +2265 -0
- package/dist/server/serve.d.ts +1 -70
- package/dist/server/serve.js +1 -1131
- package/dist/server/trace-output.d.ts +6 -0
- package/dist/server/trace-output.js +79 -0
- package/dist/server/types.d.ts +30 -5
- package/dist/server/types.js +13 -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 +9 -4
- package/dist/stealth/profiles.js +160 -211
- package/dist/stream-evidence.d.ts +74 -0
- package/dist/stream-evidence.js +785 -0
- package/dist/stream.js +7 -1
- package/dist/testing/index.d.ts +2 -1
- package/dist/testing/index.js +2 -1
- package/dist/testing/run.d.ts +32 -2
- package/dist/testing/run.js +489 -21
- package/dist/trace-sanitization.d.ts +5 -0
- package/dist/trace-sanitization.js +45 -0
- package/dist/types.d.ts +673 -131
- package/dist/types.js +1 -0
- package/package.json +45 -5
- package/src/auth-turn/index.ts +1 -1
- package/src/auth.ts +118 -0
- package/src/ceremonies/index.ts +189 -46
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/approval-override.ts.txt +6 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/codemod-syntax.ts.txt +3 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/connection-precedence.ts.txt +10 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/docs-conflict.ts.txt +8 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-hoisted-array-spread.ts.txt +15 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-imported-array-spread.ts.txt +9 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-map.ts.txt +5 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-mixed-array-spread.ts.txt +24 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-operation.ts.txt +16 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-map.ts.txt +3 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/hoist-all.ts.txt +31 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/hoisted-const.ts.txt +11 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/imported-spread.ts.txt +11 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-map.ts.txt +11 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-cast-tail.ts.txt +21 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-ekitan.ts.txt +11 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-override.ts.txt +14 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/missing-english-locale.ts.txt +7 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/no-safety.ts.txt +6 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/non-literal.ts.txt +7 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/redundant-approval.ts.txt +6 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/safety-conflict.ts.txt +7 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/stream.ts.txt +7 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/tool-router-spread.ts.txt +15 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/unparseable.ts.txt +4 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/verbatim-template.ts.txt +12 -0
- package/src/cli/commands.ts +33 -0
- package/src/cli/create.ts +50 -37
- package/src/cli/migrate-operation-declaration.ts +1751 -0
- package/src/cli/migrate-operation-shape.ts +184 -0
- package/src/cli/migrate-provider-shape.ts +772 -0
- package/src/cli/prompt-assets.ts +865 -0
- package/src/cli/templates/provider/AGENTS.md.tpl +17 -8
- package/src/cli/templates/provider/Dockerfile.tpl +1 -1
- package/src/cli/templates/provider/README.md.tpl +5 -5
- package/src/cli/templates/provider/index.ts.tpl +6 -3
- package/src/cli/templates/provider/operations/ping.ts.tpl +4 -1
- package/src/cli/templates/provider/provider.json.tpl +6 -0
- package/src/config/loader.ts +690 -163
- package/src/contract-serialization.ts +5 -7
- package/src/contract-types.ts +12 -5
- package/src/contract.ts +24 -10
- package/src/declaration-validation.ts +330 -0
- package/src/define.ts +1048 -131
- package/src/dev.ts +4 -1
- package/src/engine.ts +279 -0
- package/src/error-observability.ts +64 -0
- package/src/error-resolution.ts +127 -0
- package/src/errors.ts +68 -0
- package/src/fixture-sanitization.ts +264 -0
- package/src/health-scenario.ts +875 -0
- package/src/index.ts +220 -13
- package/src/lint.ts +698 -90
- 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 +161 -3
- package/src/runtime/auth-flow.ts +12 -0
- package/src/runtime/browser.ts +661 -63
- package/src/runtime/cache.ts +189 -14
- package/src/runtime/choice-wordlist.ts +145 -0
- package/src/runtime/choice.ts +631 -120
- package/src/runtime/chrome149-header-order.ts +330 -0
- package/src/runtime/env.ts +13 -0
- package/src/runtime/executor.ts +43 -31
- package/src/runtime/http.ts +641 -61
- package/src/runtime/insights.ts +2 -2
- package/src/runtime/instrumentation.ts +520 -15
- 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 +467 -21
- package/src/runtime/proxy-errors.ts +12 -4
- package/src/runtime/proxy-nodemaven.ts +221 -0
- package/src/runtime/proxy-telemetry.ts +244 -75
- package/src/runtime/redirects.ts +66 -0
- package/src/runtime/redis.ts +7 -2
- package/src/runtime/request-options.ts +680 -1
- package/src/runtime/resolver-config.ts +6 -0
- package/src/runtime/resolver-public.ts +23 -0
- package/src/runtime/resolver-shared.ts +33 -0
- package/src/runtime/resolver-vendors/bindings.ts +56 -0
- package/src/runtime/resolver-vendors/browser.ts +533 -0
- package/src/runtime/resolver-vendors/capsolver.ts +707 -0
- package/src/runtime/resolver-vendors/hosts.ts +38 -0
- package/src/runtime/resolver-vendors/twocaptcha.ts +540 -0
- package/src/runtime/resolver-vendors/types.ts +212 -0
- package/src/runtime/resolver.ts +1157 -0
- package/src/runtime/secrets.ts +64 -0
- package/src/runtime/state.ts +394 -77
- package/src/runtime/stealth-cookies.ts +132 -0
- package/src/runtime/stealth.ts +1280 -336
- package/src/runtime/stt.ts +1 -19
- package/src/runtime/timeout.ts +18 -0
- package/src/runtime/trace-config.ts +78 -0
- package/src/runtime/trace.ts +57 -17
- package/src/serve.ts +6 -1
- package/src/server/error-observability.ts +1 -0
- package/src/server/index.ts +34 -2
- package/src/server/self-test-input-tokens.ts +29 -14
- package/src/server/self-test.ts +191 -68
- package/src/server/serve-implementation.ts +3378 -0
- package/src/server/serve.ts +1 -1632
- package/src/server/trace-output.ts +129 -0
- package/src/server/types.ts +13 -1
- 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 +202 -231
- package/src/stream-evidence.ts +988 -0
- package/src/stream.ts +8 -1
- package/src/testing/index.ts +10 -1
- package/src/testing/run.ts +658 -15
- package/src/trace-sanitization.ts +63 -0
- package/src/types.ts +788 -174
- 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
|
@@ -64,14 +64,12 @@ function isZodSchema(schema: SchemaLike): schema is ZodType {
|
|
|
64
64
|
return schema instanceof z.ZodType;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
function zodJsonSchema(schema: ZodType): JsonValue
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
} catch (error) {
|
|
72
|
-
if (error instanceof Error) return undefined;
|
|
73
|
-
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");
|
|
74
71
|
}
|
|
72
|
+
return jsonSchema;
|
|
75
73
|
}
|
|
76
74
|
|
|
77
75
|
function getSchemaTypeName(schema: SchemaLike): string | undefined {
|
package/src/contract-types.ts
CHANGED
|
@@ -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;
|
|
@@ -29,17 +30,23 @@ export interface ProviderContractSnapshot {
|
|
|
29
30
|
|
|
30
31
|
export interface ProviderContractOperation {
|
|
31
32
|
readonly id: string;
|
|
33
|
+
readonly connectionMode?: JsonValue;
|
|
34
|
+
readonly connectionExternalRefParam?: JsonValue;
|
|
35
|
+
readonly riskClass: JsonValue;
|
|
36
|
+
readonly approval?: JsonValue;
|
|
37
|
+
readonly timeoutMs?: JsonValue;
|
|
38
|
+
readonly titleKey?: JsonValue;
|
|
32
39
|
readonly descriptionKey?: JsonValue;
|
|
33
|
-
readonly
|
|
40
|
+
readonly summaryKey?: JsonValue;
|
|
41
|
+
readonly markdownKey?: JsonValue;
|
|
34
42
|
readonly whenToUseKeys?: JsonValue;
|
|
35
43
|
readonly whenNotToUseKeys?: JsonValue;
|
|
36
|
-
readonly
|
|
37
|
-
readonly
|
|
38
|
-
readonly
|
|
44
|
+
readonly normalizationNotesKeys?: JsonValue;
|
|
45
|
+
readonly errorCodes?: JsonValue;
|
|
46
|
+
readonly examples?: JsonValue;
|
|
39
47
|
readonly contract?: JsonValue;
|
|
40
48
|
readonly tags?: JsonValue;
|
|
41
49
|
readonly relatedOperations?: JsonValue;
|
|
42
|
-
readonly toolRouter?: JsonValue;
|
|
43
50
|
readonly observability?: JsonValue;
|
|
44
51
|
readonly transport?: JsonValue;
|
|
45
52
|
readonly inputSchema: JsonValue;
|
package/src/contract.ts
CHANGED
|
@@ -35,6 +35,7 @@ export function extractProviderContract(provider: ProviderDefinition): ProviderC
|
|
|
35
35
|
const auth = extractAuth(provider.auth);
|
|
36
36
|
const stealth = toJsonValue(provider.stealth);
|
|
37
37
|
const proxy = toJsonValue(provider.proxy);
|
|
38
|
+
const ocr = toJsonValue(provider.ocr);
|
|
38
39
|
const stt = toJsonValue(provider.stt);
|
|
39
40
|
const browser = toJsonValue(provider.browser);
|
|
40
41
|
const reviewed = toJsonValue(provider.reviewed);
|
|
@@ -59,6 +60,7 @@ export function extractProviderContract(provider: ProviderDefinition): ProviderC
|
|
|
59
60
|
...(provider.allowedHosts ? { allowedHosts: [...provider.allowedHosts].sort() } : {}),
|
|
60
61
|
...(stealth === undefined ? {} : { stealth }),
|
|
61
62
|
...(proxy === undefined ? {} : { proxy }),
|
|
63
|
+
...(ocr === undefined ? {} : { ocr }),
|
|
62
64
|
...(stt === undefined ? {} : { stt }),
|
|
63
65
|
...(browser === undefined ? {} : { browser }),
|
|
64
66
|
...(auth === undefined ? {} : { auth }),
|
|
@@ -80,17 +82,22 @@ function extractOperation(
|
|
|
80
82
|
operationId: string,
|
|
81
83
|
operation: OperationDefinition,
|
|
82
84
|
): ProviderContractOperation {
|
|
85
|
+
const connectionMode = toJsonValue(operation.connectionMode);
|
|
86
|
+
const connectionExternalRefParam = toJsonValue(operation.connectionExternalRefParam);
|
|
87
|
+
const approval = toJsonValue(operation.approval);
|
|
88
|
+
const timeoutMs = toJsonValue(operation.timeoutMs);
|
|
89
|
+
const titleKey = toJsonValue(operation.titleKey);
|
|
83
90
|
const descriptionKey = toJsonValue(operation.descriptionKey);
|
|
84
|
-
const
|
|
91
|
+
const summaryKey = toJsonValue(operation.summaryKey);
|
|
92
|
+
const markdownKey = toJsonValue(operation.markdownKey);
|
|
85
93
|
const whenToUseKeys = toJsonValue(operation.whenToUseKeys);
|
|
86
94
|
const whenNotToUseKeys = toJsonValue(operation.whenNotToUseKeys);
|
|
87
|
-
const
|
|
88
|
-
const
|
|
89
|
-
const
|
|
95
|
+
const normalizationNotesKeys = toJsonValue(operation.normalizationNotesKeys);
|
|
96
|
+
const errorCodes = toJsonValue(operation.errorCodes);
|
|
97
|
+
const examples = toJsonValue(operation.examples);
|
|
90
98
|
const contract = toJsonValue(operation.contract);
|
|
91
99
|
const tags = toJsonValue(operation.tags);
|
|
92
100
|
const relatedOperations = toJsonValue(operation.relatedOperations);
|
|
93
|
-
const toolRouter = toJsonValue(operation.toolRouter);
|
|
94
101
|
const observability = toJsonValue(operation.observability);
|
|
95
102
|
const transport = extractTransport(operation.transport);
|
|
96
103
|
const fixtures = toJsonValue(operation.fixtures);
|
|
@@ -103,17 +110,23 @@ function extractOperation(
|
|
|
103
110
|
id: operationId,
|
|
104
111
|
inputSchema: describeSchema(operation.input),
|
|
105
112
|
outputSchema: describeSchema(operation.output),
|
|
113
|
+
...(connectionMode === undefined ? {} : { connectionMode }),
|
|
114
|
+
...(connectionExternalRefParam === undefined ? {} : { connectionExternalRefParam }),
|
|
115
|
+
riskClass: operation.riskClass,
|
|
116
|
+
...(approval === undefined ? {} : { approval }),
|
|
117
|
+
...(timeoutMs === undefined ? {} : { timeoutMs }),
|
|
118
|
+
...(titleKey === undefined ? {} : { titleKey }),
|
|
106
119
|
...(descriptionKey === undefined ? {} : { descriptionKey }),
|
|
107
|
-
...(
|
|
120
|
+
...(summaryKey === undefined ? {} : { summaryKey }),
|
|
121
|
+
...(markdownKey === undefined ? {} : { markdownKey }),
|
|
108
122
|
...(whenToUseKeys === undefined ? {} : { whenToUseKeys }),
|
|
109
123
|
...(whenNotToUseKeys === undefined ? {} : { whenNotToUseKeys }),
|
|
110
|
-
...(
|
|
111
|
-
...(
|
|
112
|
-
...(
|
|
124
|
+
...(normalizationNotesKeys === undefined ? {} : { normalizationNotesKeys }),
|
|
125
|
+
...(errorCodes === undefined ? {} : { errorCodes }),
|
|
126
|
+
...(examples === undefined ? {} : { examples }),
|
|
113
127
|
...(contract === undefined ? {} : { contract }),
|
|
114
128
|
...(tags === undefined ? {} : { tags }),
|
|
115
129
|
...(relatedOperations === undefined ? {} : { relatedOperations }),
|
|
116
|
-
...(toolRouter === undefined ? {} : { toolRouter }),
|
|
117
130
|
...(observability === undefined ? {} : { observability }),
|
|
118
131
|
...(transport === undefined ? {} : { transport }),
|
|
119
132
|
...(fixtures === undefined ? {} : { fixtures }),
|
|
@@ -165,6 +178,7 @@ function extractHealthCheck(value: HealthCheckSuite | undefined): JsonValue | un
|
|
|
165
178
|
name: item.name,
|
|
166
179
|
description: item.description,
|
|
167
180
|
input: toJsonValue(item.input),
|
|
181
|
+
scenario: toJsonValue(item.scenario),
|
|
168
182
|
degradedThresholdMs: item.degradedThresholdMs,
|
|
169
183
|
timeoutMs: item.timeoutMs,
|
|
170
184
|
expectedStatus: item.expectedStatus,
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
import { describeSchema } from "./contract-serialization.js";
|
|
2
|
+
import { ProviderError } from "./errors.js";
|
|
3
|
+
import { HealthScenarioSchema } from "./health-scenario.js";
|
|
4
|
+
import type {
|
|
5
|
+
HealthJourneyDefinition,
|
|
6
|
+
ProviderDefinition,
|
|
7
|
+
ProviderProxyPolicy,
|
|
8
|
+
ProviderProxyProvider,
|
|
9
|
+
} from "./types.js";
|
|
10
|
+
|
|
11
|
+
export const DECLARATION_INVALID_CODE = "DECLARATION_INVALID";
|
|
12
|
+
|
|
13
|
+
export const DECLARATION_RULE_IDS = {
|
|
14
|
+
challengeShape: "credentials-challenge-shape",
|
|
15
|
+
journeyExecutable: "health-journey-executable",
|
|
16
|
+
journeyRunScenarioExclusive: "health-journey-run-scenario-exclusive",
|
|
17
|
+
journeyScenarioValid: "health-journey-scenario-valid",
|
|
18
|
+
schemaSerializable: "operation-schema-serializable",
|
|
19
|
+
proxyExplicitPolicy: "proxy-explicit-policy",
|
|
20
|
+
proxyVendorExclusive: "proxy-vendor-fields-exclusive",
|
|
21
|
+
proxyNoMixedVendors: "proxy-no-mixed-vendors",
|
|
22
|
+
proxySmartproxyGeo: "proxy-smartproxy-country-only",
|
|
23
|
+
operationUpstreamProxy: "operation-upstream-proxy-unsupported",
|
|
24
|
+
pinnedWireFieldPathValid: "public-schema-pinned-wire-field-valid",
|
|
25
|
+
} as const;
|
|
26
|
+
|
|
27
|
+
export type DeclarationRuleId =
|
|
28
|
+
(typeof DECLARATION_RULE_IDS)[keyof typeof DECLARATION_RULE_IDS];
|
|
29
|
+
|
|
30
|
+
export type DeclarationViolation = {
|
|
31
|
+
ruleId: DeclarationRuleId;
|
|
32
|
+
path: string;
|
|
33
|
+
message: string;
|
|
34
|
+
fix: string;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export function declarationInvalidError(
|
|
38
|
+
violations: readonly DeclarationViolation[],
|
|
39
|
+
): ProviderError {
|
|
40
|
+
const summary = violations
|
|
41
|
+
.map((violation) => `${violation.path} [${violation.ruleId}]: ${violation.message}`)
|
|
42
|
+
.join("\n");
|
|
43
|
+
return new ProviderError(
|
|
44
|
+
`Provider declaration is invalid (${violations.length} violation${violations.length === 1 ? "" : "s"}).${summary ? `\n${summary}` : ""}`,
|
|
45
|
+
{
|
|
46
|
+
code: DECLARATION_INVALID_CODE,
|
|
47
|
+
details: { violations: [...violations] },
|
|
48
|
+
fix: "Apply every violation's fix hint, then validate the declaration again.",
|
|
49
|
+
},
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Enforces declaration rules whose runtime behavior would otherwise fail open. */
|
|
54
|
+
export function validateFailClosedDeclaration(provider: ProviderDefinition): void {
|
|
55
|
+
const violations: DeclarationViolation[] = [];
|
|
56
|
+
validateHealthDeclaration(provider, violations);
|
|
57
|
+
validatePinnedWireFieldPaths(provider, violations);
|
|
58
|
+
validateSchemaDeclaration(provider, violations);
|
|
59
|
+
validateProxyDeclaration(provider, violations);
|
|
60
|
+
validateOperationDeclaration(provider, violations);
|
|
61
|
+
if (violations.length > 0) throw declarationInvalidError(violations);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
type ProviderDeclarationRulesInput = Pick<ProviderDefinition, "healthJourneys" | "meta" | "proxy">;
|
|
65
|
+
type OperationDeclarationRulesInput = Pick<ProviderDefinition, "operations">;
|
|
66
|
+
|
|
67
|
+
/** Enforces fail-closed rules that only depend on the provider declaration. */
|
|
68
|
+
export function validateFailClosedProviderDeclaration(
|
|
69
|
+
provider: ProviderDeclarationRulesInput,
|
|
70
|
+
): void {
|
|
71
|
+
const violations: DeclarationViolation[] = [];
|
|
72
|
+
collectProviderDeclarationViolations(provider, violations);
|
|
73
|
+
if (violations.length > 0) throw declarationInvalidError(violations);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Enforces fail-closed rules that depend on the operation implementation. */
|
|
77
|
+
export function validateFailClosedOperationDeclaration(
|
|
78
|
+
provider: OperationDeclarationRulesInput,
|
|
79
|
+
): void {
|
|
80
|
+
const violations: DeclarationViolation[] = [];
|
|
81
|
+
collectOperationDeclarationViolations(provider, violations);
|
|
82
|
+
if (violations.length > 0) throw declarationInvalidError(violations);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function collectProviderDeclarationViolations(
|
|
86
|
+
provider: ProviderDeclarationRulesInput,
|
|
87
|
+
violations: DeclarationViolation[],
|
|
88
|
+
): void {
|
|
89
|
+
validateHealthDeclaration(provider, violations);
|
|
90
|
+
validatePinnedWireFieldPaths(provider, violations);
|
|
91
|
+
validateProxyDeclaration(provider, violations);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function validatePinnedWireFieldPaths(
|
|
95
|
+
provider: ProviderDeclarationRulesInput,
|
|
96
|
+
violations: DeclarationViolation[],
|
|
97
|
+
): void {
|
|
98
|
+
const pins = provider.meta?.contract?.pinnedWireFieldPaths;
|
|
99
|
+
if (pins === undefined) return;
|
|
100
|
+
|
|
101
|
+
if (!Array.isArray(pins)) {
|
|
102
|
+
violations.push({
|
|
103
|
+
ruleId: DECLARATION_RULE_IDS.pinnedWireFieldPathValid,
|
|
104
|
+
path: "meta.contract.pinnedWireFieldPaths",
|
|
105
|
+
message: "pinned wire field paths must be an array.",
|
|
106
|
+
fix: "Declare a readonly array of { path, reason } entries.",
|
|
107
|
+
});
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const seenPaths = new Set<string>();
|
|
112
|
+
for (const [index, pin] of pins.entries()) {
|
|
113
|
+
const entryPath = `meta.contract.pinnedWireFieldPaths[${index}]`;
|
|
114
|
+
if (!pin || typeof pin !== "object" || Array.isArray(pin)) {
|
|
115
|
+
violations.push({
|
|
116
|
+
ruleId: DECLARATION_RULE_IDS.pinnedWireFieldPathValid,
|
|
117
|
+
path: entryPath,
|
|
118
|
+
message: "each pinned wire field path must be an object.",
|
|
119
|
+
fix: `Replace ${entryPath} with { path: "operations.<operation-id>.<field-path>", reason: "<non-empty reason>" }.`,
|
|
120
|
+
});
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const path = "path" in pin ? pin.path : undefined;
|
|
125
|
+
const reason = "reason" in pin ? pin.reason : undefined;
|
|
126
|
+
if (typeof path !== "string" || path.trim().length === 0) {
|
|
127
|
+
violations.push({
|
|
128
|
+
ruleId: DECLARATION_RULE_IDS.pinnedWireFieldPathValid,
|
|
129
|
+
path: `${entryPath}.path`,
|
|
130
|
+
message: "path must be a non-empty string.",
|
|
131
|
+
fix: `Set ${entryPath}.path to the exact public-schema-upstream-field diagnostic path.`,
|
|
132
|
+
});
|
|
133
|
+
} else if (seenPaths.has(path)) {
|
|
134
|
+
violations.push({
|
|
135
|
+
ruleId: DECLARATION_RULE_IDS.pinnedWireFieldPathValid,
|
|
136
|
+
path: `${entryPath}.path`,
|
|
137
|
+
message: `duplicate pinned wire field path ${JSON.stringify(path)}.`,
|
|
138
|
+
fix: `Keep exactly one declaration for ${JSON.stringify(path)}.`,
|
|
139
|
+
});
|
|
140
|
+
} else {
|
|
141
|
+
seenPaths.add(path);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (typeof reason !== "string" || reason.trim().length === 0) {
|
|
145
|
+
violations.push({
|
|
146
|
+
ruleId: DECLARATION_RULE_IDS.pinnedWireFieldPathValid,
|
|
147
|
+
path: `${entryPath}.reason`,
|
|
148
|
+
message: "reason must be a non-empty string.",
|
|
149
|
+
fix: `Document why renaming the exact wire field would break the upstream contract.`,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function collectOperationDeclarationViolations(
|
|
156
|
+
provider: OperationDeclarationRulesInput,
|
|
157
|
+
violations: DeclarationViolation[],
|
|
158
|
+
): void {
|
|
159
|
+
validateSchemaDeclaration(provider, violations);
|
|
160
|
+
validateOperationDeclaration(provider, violations);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function validateHealthDeclaration(
|
|
164
|
+
provider: ProviderDeclarationRulesInput,
|
|
165
|
+
violations: DeclarationViolation[],
|
|
166
|
+
): void {
|
|
167
|
+
for (const [index, journey] of (provider.healthJourneys ?? []).entries()) {
|
|
168
|
+
if (!journey || typeof journey !== "object") continue;
|
|
169
|
+
const hasRun = journey.run !== undefined;
|
|
170
|
+
const hasScenario = journey.scenario !== undefined;
|
|
171
|
+
if (hasRun && hasScenario) {
|
|
172
|
+
const journeyPath = healthJourneyPath(journey, index);
|
|
173
|
+
violations.push({
|
|
174
|
+
ruleId: DECLARATION_RULE_IDS.journeyRunScenarioExclusive,
|
|
175
|
+
path: journeyPath,
|
|
176
|
+
message: "A health journey must declare exactly one of run or scenario, not both.",
|
|
177
|
+
fix: `Remove either ${journeyPath}.run or ${journeyPath}.scenario.`,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
if (!hasRun && !hasScenario) {
|
|
181
|
+
const journeyPath = healthJourneyPath(journey, index);
|
|
182
|
+
violations.push({
|
|
183
|
+
ruleId: DECLARATION_RULE_IDS.journeyExecutable,
|
|
184
|
+
path: `${journeyPath}.run`,
|
|
185
|
+
message:
|
|
186
|
+
"coversOperations cannot provide health coverage without run or a declarative scenario.",
|
|
187
|
+
fix: `Add an async run(ctx) implementation or a valid scenario to ${journeyPath}.`,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
if (hasScenario) {
|
|
191
|
+
const parsed = HealthScenarioSchema.safeParse(journey.scenario);
|
|
192
|
+
if (!parsed.success) {
|
|
193
|
+
const journeyPath = healthJourneyPath(journey, index);
|
|
194
|
+
violations.push({
|
|
195
|
+
ruleId: DECLARATION_RULE_IDS.journeyScenarioValid,
|
|
196
|
+
path: `${journeyPath}.scenario`,
|
|
197
|
+
message: "scenario must conform to HealthScenario.",
|
|
198
|
+
fix: "Build the scenario with defineHealthScenario().",
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// NOTE: healthCheck.cases[].enabled is intentionally NOT validated here.
|
|
205
|
+
// self-test.ts reports a gated case as status "skipped" with skipReason
|
|
206
|
+
// "disabled", so the skip is visible in results rather than silent — it is a
|
|
207
|
+
// supported conditional-execution feature, not a class-1 silent no-op.
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function healthJourneyPath(journey: HealthJourneyDefinition, index: number): string {
|
|
211
|
+
return typeof journey.id === "string" && journey.id.length > 0
|
|
212
|
+
? `healthJourneys.${journey.id}`
|
|
213
|
+
: `healthJourneys[${index}]`;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function validateSchemaDeclaration(
|
|
217
|
+
provider: OperationDeclarationRulesInput,
|
|
218
|
+
violations: DeclarationViolation[],
|
|
219
|
+
): void {
|
|
220
|
+
for (const [operationId, operation] of Object.entries(provider.operations ?? {})) {
|
|
221
|
+
const schemaEntries: Array<[string, unknown]> = [
|
|
222
|
+
[`operations.${operationId}.input`, operation.input],
|
|
223
|
+
[`operations.${operationId}.output`, operation.output],
|
|
224
|
+
];
|
|
225
|
+
// SSE event schemas reach contract extraction the same way input/output do,
|
|
226
|
+
// so a transform-bearing event schema would abort extraction at runtime while
|
|
227
|
+
// passing declaration checks. Validate them under the same rule.
|
|
228
|
+
const transport = operation.transport;
|
|
229
|
+
if (transport?.kind === "sse") {
|
|
230
|
+
for (const [eventName, eventSchema] of Object.entries(transport.events ?? {})) {
|
|
231
|
+
schemaEntries.push([
|
|
232
|
+
`operations.${operationId}.transport.events.${eventName}`,
|
|
233
|
+
eventSchema,
|
|
234
|
+
]);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
for (const [path, schema] of schemaEntries) {
|
|
238
|
+
try {
|
|
239
|
+
describeSchema(schema as Parameters<typeof describeSchema>[0]);
|
|
240
|
+
} catch (error) {
|
|
241
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
242
|
+
violations.push({
|
|
243
|
+
ruleId: DECLARATION_RULE_IDS.schemaSerializable,
|
|
244
|
+
path,
|
|
245
|
+
message: `schema conversion to JSON Schema failed: ${reason}`,
|
|
246
|
+
fix: `Replace unsupported constructs in ${path} so z.toJSONSchema() succeeds.`,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const MANAGED_PROXY_VENDORS = new Set<ProviderProxyProvider>(["smartproxy", "nodemaven"]);
|
|
254
|
+
const STATIC_PROXY_VENDORS = new Set<ProviderProxyProvider>(["custom", "decodo"]);
|
|
255
|
+
|
|
256
|
+
function validateProxyDeclaration(
|
|
257
|
+
provider: ProviderDeclarationRulesInput,
|
|
258
|
+
violations: DeclarationViolation[],
|
|
259
|
+
): void {
|
|
260
|
+
if (provider.proxy === true) {
|
|
261
|
+
violations.push({
|
|
262
|
+
ruleId: DECLARATION_RULE_IDS.proxyExplicitPolicy,
|
|
263
|
+
path: "proxy",
|
|
264
|
+
message: "proxy: true does not require resolvable proxy egress.",
|
|
265
|
+
fix: 'Replace proxy: true with an explicit policy such as proxy: { mode: "required", providers: ["smartproxy"] }.',
|
|
266
|
+
});
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
if (!provider.proxy || typeof provider.proxy !== "object") return;
|
|
270
|
+
|
|
271
|
+
const policy = provider.proxy as ProviderProxyPolicy;
|
|
272
|
+
const hasProvider = policy.provider !== undefined;
|
|
273
|
+
const hasProviders = policy.providers !== undefined;
|
|
274
|
+
if (hasProvider && hasProviders) {
|
|
275
|
+
violations.push({
|
|
276
|
+
ruleId: DECLARATION_RULE_IDS.proxyVendorExclusive,
|
|
277
|
+
path: "proxy",
|
|
278
|
+
message: "provider and providers are ambiguous when declared together.",
|
|
279
|
+
fix: "Keep either proxy.provider or proxy.providers, and remove the other field.",
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const vendors = declaredProxyVendors(policy);
|
|
284
|
+
if (
|
|
285
|
+
vendors.some((vendor) => MANAGED_PROXY_VENDORS.has(vendor)) &&
|
|
286
|
+
vendors.some((vendor) => STATIC_PROXY_VENDORS.has(vendor))
|
|
287
|
+
) {
|
|
288
|
+
violations.push({
|
|
289
|
+
ruleId: DECLARATION_RULE_IDS.proxyNoMixedVendors,
|
|
290
|
+
path: hasProviders ? "proxy.providers" : "proxy.provider",
|
|
291
|
+
message: "managed and deprecated static proxy vendors cannot share a chain.",
|
|
292
|
+
fix: "Use only smartproxy/nodemaven vendors, or only deprecated static markers, in one policy.",
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (vendors.includes("smartproxy")) {
|
|
297
|
+
for (const field of ["subdivision", "city"] as const) {
|
|
298
|
+
if (policy.geo?.[field] === undefined) continue;
|
|
299
|
+
const path = `proxy.geo.${field}`;
|
|
300
|
+
violations.push({
|
|
301
|
+
ruleId: DECLARATION_RULE_IDS.proxySmartproxyGeo,
|
|
302
|
+
path,
|
|
303
|
+
message: `smartproxy cannot honor ${field}-level geo targeting.`,
|
|
304
|
+
fix: `Remove ${path} or use a vendor chain that can honor it.`,
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function declaredProxyVendors(policy: ProviderProxyPolicy): ProviderProxyProvider[] {
|
|
311
|
+
const vendors = [...(policy.providers ?? [])];
|
|
312
|
+
if (policy.provider !== undefined) vendors.push(policy.provider);
|
|
313
|
+
return vendors;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function validateOperationDeclaration(
|
|
317
|
+
provider: OperationDeclarationRulesInput,
|
|
318
|
+
violations: DeclarationViolation[],
|
|
319
|
+
): void {
|
|
320
|
+
for (const [operationId, operation] of Object.entries(provider.operations ?? {})) {
|
|
321
|
+
if (!operation.upstream?.proxy) continue;
|
|
322
|
+
const path = `operations.${operationId}.upstream.proxy`;
|
|
323
|
+
violations.push({
|
|
324
|
+
ruleId: DECLARATION_RULE_IDS.operationUpstreamProxy,
|
|
325
|
+
path,
|
|
326
|
+
message: "operation-level proxy policy is not wired into operation execution.",
|
|
327
|
+
fix: `Remove ${path} and declare the effective policy at provider.proxy.`,
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
}
|