@apifuse/provider-sdk 2.2.0-beta.37 → 2.2.0-beta.39
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/CHANGELOG.md +8 -0
- package/dist/declaration-validation.d.ts +9 -0
- package/dist/declaration-validation.js +51 -3
- package/dist/define.d.ts +2 -2
- package/dist/define.js +37 -22
- package/dist/health-scenario.d.ts +1842 -0
- package/dist/health-scenario.js +624 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +1 -0
- package/dist/provider.d.ts +3 -0
- package/dist/provider.js +1 -0
- package/dist/runtime/executor.d.ts +2 -2
- package/dist/runtime/executor.js +3 -1
- package/dist/runtime/instrumentation.d.ts +2 -2
- package/dist/runtime/proxy-telemetry.d.ts +41 -1
- package/dist/runtime/proxy-telemetry.js +59 -56
- package/dist/server/index.d.ts +2 -0
- package/dist/server/serve-implementation.d.ts +3 -1
- package/dist/server/serve-implementation.js +81 -30
- package/dist/server/types.d.ts +4 -4
- package/dist/types.d.ts +10 -8
- package/package.json +1 -1
- package/src/declaration-validation.ts +71 -7
- package/src/define.ts +61 -38
- package/src/health-scenario.ts +875 -0
- package/src/index.ts +78 -0
- package/src/provider.ts +75 -0
- package/src/runtime/executor.ts +11 -6
- package/src/runtime/instrumentation.ts +5 -2
- package/src/runtime/proxy-telemetry.ts +100 -99
- package/src/server/index.ts +8 -0
- package/src/server/serve-implementation.ts +90 -8
- package/src/types.ts +11 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# @apifuse/provider-sdk Changelog
|
|
2
2
|
|
|
3
|
+
## 2.2.0-beta.39
|
|
4
|
+
|
|
5
|
+
- Release candidate for main commit ecbe349c44e15c873b7c58b42e14610db029eb5f.
|
|
6
|
+
|
|
7
|
+
## 2.2.0-beta.38
|
|
8
|
+
|
|
9
|
+
- Release candidate for main commit 448775077dbc9ab907209f1feee4e6e4e5ef4283.
|
|
10
|
+
|
|
3
11
|
## 2.2.0-beta.37
|
|
4
12
|
|
|
5
13
|
- Release candidate for main commit aa14b268dffe1196f25c2b6b314598fe0896edec.
|
|
@@ -4,6 +4,8 @@ export declare const DECLARATION_INVALID_CODE = "DECLARATION_INVALID";
|
|
|
4
4
|
export declare const DECLARATION_RULE_IDS: {
|
|
5
5
|
readonly challengeShape: "credentials-challenge-shape";
|
|
6
6
|
readonly journeyExecutable: "health-journey-executable";
|
|
7
|
+
readonly journeyRunScenarioExclusive: "health-journey-run-scenario-exclusive";
|
|
8
|
+
readonly journeyScenarioValid: "health-journey-scenario-valid";
|
|
7
9
|
readonly schemaSerializable: "operation-schema-serializable";
|
|
8
10
|
readonly proxyExplicitPolicy: "proxy-explicit-policy";
|
|
9
11
|
readonly proxyVendorExclusive: "proxy-vendor-fields-exclusive";
|
|
@@ -21,3 +23,10 @@ export type DeclarationViolation = {
|
|
|
21
23
|
export declare function declarationInvalidError(violations: readonly DeclarationViolation[]): ProviderError;
|
|
22
24
|
/** Enforces declaration rules whose runtime behavior would otherwise fail open. */
|
|
23
25
|
export declare function validateFailClosedDeclaration(provider: ProviderDefinition): void;
|
|
26
|
+
type ProviderDeclarationRulesInput = Pick<ProviderDefinition, "healthJourneys" | "proxy">;
|
|
27
|
+
type OperationDeclarationRulesInput = Pick<ProviderDefinition, "operations">;
|
|
28
|
+
/** Enforces fail-closed rules that only depend on the provider declaration. */
|
|
29
|
+
export declare function validateFailClosedProviderDeclaration(provider: ProviderDeclarationRulesInput): void;
|
|
30
|
+
/** Enforces fail-closed rules that depend on the operation implementation. */
|
|
31
|
+
export declare function validateFailClosedOperationDeclaration(provider: OperationDeclarationRulesInput): void;
|
|
32
|
+
export {};
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { describeSchema } from "./contract-serialization.js";
|
|
2
2
|
import { ProviderError } from "./errors.js";
|
|
3
|
+
import { HealthScenarioSchema } from "./health-scenario.js";
|
|
3
4
|
export const DECLARATION_INVALID_CODE = "DECLARATION_INVALID";
|
|
4
5
|
export const DECLARATION_RULE_IDS = {
|
|
5
6
|
challengeShape: "credentials-challenge-shape",
|
|
6
7
|
journeyExecutable: "health-journey-executable",
|
|
8
|
+
journeyRunScenarioExclusive: "health-journey-run-scenario-exclusive",
|
|
9
|
+
journeyScenarioValid: "health-journey-scenario-valid",
|
|
7
10
|
schemaSerializable: "operation-schema-serializable",
|
|
8
11
|
proxyExplicitPolicy: "proxy-explicit-policy",
|
|
9
12
|
proxyVendorExclusive: "proxy-vendor-fields-exclusive",
|
|
@@ -31,19 +34,64 @@ export function validateFailClosedDeclaration(provider) {
|
|
|
31
34
|
if (violations.length > 0)
|
|
32
35
|
throw declarationInvalidError(violations);
|
|
33
36
|
}
|
|
37
|
+
/** Enforces fail-closed rules that only depend on the provider declaration. */
|
|
38
|
+
export function validateFailClosedProviderDeclaration(provider) {
|
|
39
|
+
const violations = [];
|
|
40
|
+
collectProviderDeclarationViolations(provider, violations);
|
|
41
|
+
if (violations.length > 0)
|
|
42
|
+
throw declarationInvalidError(violations);
|
|
43
|
+
}
|
|
44
|
+
/** Enforces fail-closed rules that depend on the operation implementation. */
|
|
45
|
+
export function validateFailClosedOperationDeclaration(provider) {
|
|
46
|
+
const violations = [];
|
|
47
|
+
collectOperationDeclarationViolations(provider, violations);
|
|
48
|
+
if (violations.length > 0)
|
|
49
|
+
throw declarationInvalidError(violations);
|
|
50
|
+
}
|
|
51
|
+
function collectProviderDeclarationViolations(provider, violations) {
|
|
52
|
+
validateHealthDeclaration(provider, violations);
|
|
53
|
+
validateProxyDeclaration(provider, violations);
|
|
54
|
+
}
|
|
55
|
+
function collectOperationDeclarationViolations(provider, violations) {
|
|
56
|
+
validateSchemaDeclaration(provider, violations);
|
|
57
|
+
validateOperationDeclaration(provider, violations);
|
|
58
|
+
}
|
|
34
59
|
function validateHealthDeclaration(provider, violations) {
|
|
35
60
|
for (const [index, journey] of (provider.healthJourneys ?? []).entries()) {
|
|
36
61
|
if (!journey || typeof journey !== "object")
|
|
37
62
|
continue;
|
|
38
|
-
|
|
63
|
+
const hasRun = journey.run !== undefined;
|
|
64
|
+
const hasScenario = journey.scenario !== undefined;
|
|
65
|
+
if (hasRun && hasScenario) {
|
|
66
|
+
const journeyPath = healthJourneyPath(journey, index);
|
|
67
|
+
violations.push({
|
|
68
|
+
ruleId: DECLARATION_RULE_IDS.journeyRunScenarioExclusive,
|
|
69
|
+
path: journeyPath,
|
|
70
|
+
message: "A health journey must declare exactly one of run or scenario, not both.",
|
|
71
|
+
fix: `Remove either ${journeyPath}.run or ${journeyPath}.scenario.`,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
if (!hasRun && !hasScenario) {
|
|
39
75
|
const journeyPath = healthJourneyPath(journey, index);
|
|
40
76
|
violations.push({
|
|
41
77
|
ruleId: DECLARATION_RULE_IDS.journeyExecutable,
|
|
42
78
|
path: `${journeyPath}.run`,
|
|
43
|
-
message: "coversOperations cannot provide health coverage without
|
|
44
|
-
fix: `Add an async run(ctx) implementation to ${journeyPath}.`,
|
|
79
|
+
message: "coversOperations cannot provide health coverage without run or a declarative scenario.",
|
|
80
|
+
fix: `Add an async run(ctx) implementation or a valid scenario to ${journeyPath}.`,
|
|
45
81
|
});
|
|
46
82
|
}
|
|
83
|
+
if (hasScenario) {
|
|
84
|
+
const parsed = HealthScenarioSchema.safeParse(journey.scenario);
|
|
85
|
+
if (!parsed.success) {
|
|
86
|
+
const journeyPath = healthJourneyPath(journey, index);
|
|
87
|
+
violations.push({
|
|
88
|
+
ruleId: DECLARATION_RULE_IDS.journeyScenarioValid,
|
|
89
|
+
path: `${journeyPath}.scenario`,
|
|
90
|
+
message: "scenario must conform to HealthScenario.",
|
|
91
|
+
fix: "Build the scenario with defineHealthScenario().",
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
47
95
|
}
|
|
48
96
|
// NOTE: healthCheck.cases[].enabled is intentionally NOT validated here.
|
|
49
97
|
// self-test.ts reports a gated case as status "skipped" with skipReason
|
package/dist/define.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AuthConfig, BrowserEngine, ContextDeclaration, CredentialDeclaration, HealthJourneyDefinition, HealthJourneySchedule, HealthScheduleRandomization, InferSchemaOutput, NativeProviderConfig, OperationDefinition, OperationHandlerResult, OperationHttpStreamTransport, OperationSseTransport, OperationWebSocketTransport, ProviderAccessConfig,
|
|
1
|
+
import type { AuthConfig, BrowserEngine, ContextDeclaration, CredentialDeclaration, HealthJourneyDefinition, HealthJourneySchedule, HealthScheduleRandomization, InferSchemaOutput, NativeProviderConfig, OperationDefinition, OperationHandlerResult, OperationHttpStreamTransport, OperationSseTransport, OperationWebSocketTransport, ProviderAccessConfig, ProviderContext, ProviderContextFor, ProviderDefinition, ProviderDeploymentOverrides, ProviderHealthMonitorConfig, ProviderOcrConfig, ProviderProxyConfig, ProviderPublicProfile, ProviderResolverConfig, ProviderReviewed, ProviderSecretDeclaration, ProviderStreamEvent, ProviderSttConfig, SchemaLike, SmsOtpMatcherDefinition, StealthPlatform } from "./types.js";
|
|
2
2
|
type ProviderImplementationSourceAccess = "official_api" | "private_api" | "browser_flow" | "hybrid";
|
|
3
3
|
type ProviderImplementationCredentialStrategy = "apifuse_managed" | "workspace_secret" | "user_oauth" | "user_session" | "none";
|
|
4
4
|
interface ProviderImplementationProfile {
|
|
@@ -125,7 +125,7 @@ export declare function defineHealthJourney(config: HealthJourneyDefinition): He
|
|
|
125
125
|
/** The second authoring phase for a declaration established by defineProvider. */
|
|
126
126
|
export type ProviderBuilder<TDeclaration extends ProviderDeclaration> = <TOperations extends Record<string, ProviderOperation>>(implementation: {
|
|
127
127
|
operations: OperationMapConfig<TOperations, ProviderContextFor<TDeclaration>>;
|
|
128
|
-
}) => ProviderDefinition & {
|
|
128
|
+
}) => Omit<ProviderDefinition, "operations"> & {
|
|
129
129
|
operations: OperationMapConfig<TOperations, ProviderContextFor<TDeclaration>>;
|
|
130
130
|
};
|
|
131
131
|
/** Extract the declaration-derived operation context from a provider builder. */
|
package/dist/define.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import ms from "ms";
|
|
2
|
-
import {
|
|
2
|
+
import { validateFailClosedOperationDeclaration, validateFailClosedProviderDeclaration, } from "./declaration-validation.js";
|
|
3
3
|
import { SDK_RUNTIME_OWNED_ERROR_CODES } from "./error-resolution.js";
|
|
4
4
|
import { ProviderError, ValidationError } from "./errors.js";
|
|
5
5
|
import { NativeEgressPolicyValidationError, validateNativeProviderConfig, } from "./native-egress-policy.js";
|
|
@@ -553,13 +553,12 @@ function validateProxiedOAuthAuth(auth, providerId) {
|
|
|
553
553
|
validateProxiedOAuthParams(config.authorizeParams, "authorizeParams", providerId);
|
|
554
554
|
validateProxiedOAuthParams(config.tokenParams, "tokenParams", providerId);
|
|
555
555
|
}
|
|
556
|
-
function
|
|
556
|
+
function validateProviderDeclarationShape(config) {
|
|
557
557
|
assertObjectConfig(config);
|
|
558
558
|
assertRequiredField(config, "id");
|
|
559
559
|
assertRequiredField(config, "version", String(config.id));
|
|
560
560
|
assertRequiredField(config, "runtime", String(config.id));
|
|
561
561
|
assertRequiredField(config, "meta", String(config.id));
|
|
562
|
-
assertRequiredField(config, "operations", String(config.id));
|
|
563
562
|
if (typeof config.runtime === "string")
|
|
564
563
|
assertLiteralField(config.runtime, "runtime", VALID_RUNTIMES, String(config.id));
|
|
565
564
|
if (config.native !== undefined && config.runtime === "browser") {
|
|
@@ -629,6 +628,10 @@ function validateProviderShape(config) {
|
|
|
629
628
|
}
|
|
630
629
|
}
|
|
631
630
|
}
|
|
631
|
+
function validateProviderImplementationShape(config) {
|
|
632
|
+
const configRecord = config;
|
|
633
|
+
assertRequiredField(configRecord, "operations", String(config.id));
|
|
634
|
+
}
|
|
632
635
|
function validateProviderProxy(config) {
|
|
633
636
|
const proxy = config.proxy;
|
|
634
637
|
if (proxy === undefined || typeof proxy === "boolean") {
|
|
@@ -1413,6 +1416,7 @@ const HEALTH_JOURNEY_FIELDS = new Set([
|
|
|
1413
1416
|
"manualTrigger",
|
|
1414
1417
|
"steps",
|
|
1415
1418
|
"run",
|
|
1419
|
+
"scenario",
|
|
1416
1420
|
]);
|
|
1417
1421
|
const HEALTH_JOURNEY_SCHEDULE_FIELDS = new Set(["kind", "interval", "jitter", "randomize"]);
|
|
1418
1422
|
const HEALTH_JOURNEY_STEP_FIELDS = new Set([
|
|
@@ -1835,6 +1839,10 @@ function validateHealthJourneys(providerId, operations, healthJourneys) {
|
|
|
1835
1839
|
}
|
|
1836
1840
|
if (journey.manualTrigger !== undefined)
|
|
1837
1841
|
validateHealthJourneyManualTrigger(providerId, journey.id, journey.manualTrigger);
|
|
1842
|
+
if (journey.scenario !== undefined && journey.smsMatchers !== undefined)
|
|
1843
|
+
throw new ValidationError(`Provider "${providerId}" healthJourneys.${journey.id}.smsMatchers is not allowed on declarative scenarios.`);
|
|
1844
|
+
if (journey.scenario !== undefined && journey.requiredSecrets !== undefined)
|
|
1845
|
+
throw new ValidationError(`Provider "${providerId}" healthJourneys.${journey.id}.requiredSecrets is not allowed on declarative scenarios.`);
|
|
1838
1846
|
if (journey.timeout !== undefined)
|
|
1839
1847
|
assertIsoDuration(journey.timeout, `Provider "${providerId}" healthJourneys.${journey.id}.timeout`);
|
|
1840
1848
|
if (journey.cooldown !== undefined)
|
|
@@ -1946,38 +1954,24 @@ function validateProviderDeployment(providerId, deployment) {
|
|
|
1946
1954
|
}
|
|
1947
1955
|
/** Establish a provider declaration before its operations are contextually typed. */
|
|
1948
1956
|
export function defineProvider(declaration) {
|
|
1957
|
+
validateProviderDeclaration(declaration);
|
|
1949
1958
|
const buildProvider = (implementation) => finalizeProvider({
|
|
1950
1959
|
...declaration,
|
|
1951
1960
|
...implementation,
|
|
1952
1961
|
});
|
|
1953
1962
|
return buildProvider;
|
|
1954
1963
|
}
|
|
1955
|
-
function
|
|
1956
|
-
|
|
1957
|
-
const operations = resolveOperationFixtureRequests(config.operations);
|
|
1964
|
+
function validateProviderDeclaration(config) {
|
|
1965
|
+
validateProviderDeclarationShape(config);
|
|
1958
1966
|
if (!CONNECTOR_ID_REGEX.test(config.id))
|
|
1959
1967
|
throw new ProviderError(`Invalid provider id: "${config.id}"`, {
|
|
1960
1968
|
fix: 'Use lowercase alphanumeric with dashes, e.g., "korea-air-quality"',
|
|
1961
1969
|
});
|
|
1962
|
-
if (Object.keys(config.operations).length === 0)
|
|
1963
|
-
throw new ProviderError(`Provider "${config.id}" must define at least one operation`, {
|
|
1964
|
-
fix: "Add at least one operation to the operations object",
|
|
1965
|
-
});
|
|
1966
|
-
validateOperationIds(config.id, config.operations);
|
|
1967
|
-
validateOperationAnnotations(config.id, config.operations);
|
|
1968
|
-
validateOperationObservability(config.id, config.operations);
|
|
1969
|
-
validateOperationErrorCodes(config.id, config.operations);
|
|
1970
|
-
validateOperationTransports(config.id, config.operations);
|
|
1971
|
-
validateOperationContracts(config.id, config.operations);
|
|
1972
|
-
validateToolRouterMetadata(config.id, config.operations);
|
|
1973
|
-
const journeyCoveredOperations = validateHealthJourneys(config.id, config.operations, config.healthJourneys);
|
|
1974
|
-
validateOperationHealthChecks(config.id, config.operations, journeyCoveredOperations);
|
|
1975
1970
|
if (config.healthMonitor !== undefined && config.healthProbe !== undefined)
|
|
1976
1971
|
throw new ValidationError(`Provider "${config.id}" declares both healthMonitor and healthProbe. They are aliases; declare exactly one.`, {
|
|
1977
1972
|
fix: "Keep healthProbe (the new name) and delete the healthMonitor block.",
|
|
1978
1973
|
});
|
|
1979
1974
|
validateProviderHealthMonitor(config.id, config.healthProbe ?? config.healthMonitor, config.healthProbe !== undefined ? "healthProbe" : "healthMonitor");
|
|
1980
|
-
validateOperationFixtures(config.id, operations);
|
|
1981
1975
|
validateProviderDeployment(config.id, config.deployment);
|
|
1982
1976
|
try {
|
|
1983
1977
|
validateNativeProviderConfig(config.native);
|
|
@@ -1997,6 +1991,25 @@ function finalizeProvider(config) {
|
|
|
1997
1991
|
});
|
|
1998
1992
|
if (config.browser && config.runtime !== "browser")
|
|
1999
1993
|
throw new ProviderError(`Provider "${config.id}" cannot define browser config unless runtime is "browser"`, { fix: 'Set runtime: "browser" or remove the browser config' });
|
|
1994
|
+
validateFailClosedProviderDeclaration(config);
|
|
1995
|
+
}
|
|
1996
|
+
function finalizeProvider(config) {
|
|
1997
|
+
validateProviderImplementationShape(config);
|
|
1998
|
+
const operations = resolveOperationFixtureRequests(config.operations);
|
|
1999
|
+
if (Object.keys(config.operations).length === 0)
|
|
2000
|
+
throw new ProviderError(`Provider "${config.id}" must define at least one operation`, {
|
|
2001
|
+
fix: "Add at least one operation to the operations object",
|
|
2002
|
+
});
|
|
2003
|
+
validateOperationIds(config.id, config.operations);
|
|
2004
|
+
validateOperationAnnotations(config.id, config.operations);
|
|
2005
|
+
validateOperationObservability(config.id, config.operations);
|
|
2006
|
+
validateOperationErrorCodes(config.id, config.operations);
|
|
2007
|
+
validateOperationTransports(config.id, config.operations);
|
|
2008
|
+
validateOperationContracts(config.id, config.operations);
|
|
2009
|
+
validateToolRouterMetadata(config.id, config.operations);
|
|
2010
|
+
const journeyCoveredOperations = validateHealthJourneys(config.id, config.operations, config.healthJourneys);
|
|
2011
|
+
validateOperationHealthChecks(config.id, config.operations, journeyCoveredOperations);
|
|
2012
|
+
validateOperationFixtures(config.id, operations);
|
|
2000
2013
|
const provider = {
|
|
2001
2014
|
id: config.id,
|
|
2002
2015
|
version: config.version,
|
|
@@ -2019,13 +2032,15 @@ function finalizeProvider(config) {
|
|
|
2019
2032
|
credential: config.credential,
|
|
2020
2033
|
context: config.context,
|
|
2021
2034
|
meta: config.meta,
|
|
2022
|
-
operations
|
|
2035
|
+
operations,
|
|
2023
2036
|
// Transitional healthMonitor → healthProbe alias: mirror whichever field
|
|
2024
2037
|
// was declared onto both so old and new consumers keep working.
|
|
2025
2038
|
healthMonitor: config.healthMonitor ?? config.healthProbe,
|
|
2026
2039
|
healthProbe: config.healthProbe ?? config.healthMonitor,
|
|
2027
2040
|
healthJourneys: config.healthJourneys,
|
|
2028
2041
|
};
|
|
2029
|
-
|
|
2042
|
+
// Declaration validation never invokes handlers, so their declaration-bound
|
|
2043
|
+
// context parameter is irrelevant to the runtime ProviderDefinition shape.
|
|
2044
|
+
validateFailClosedOperationDeclaration(provider);
|
|
2030
2045
|
return provider;
|
|
2031
2046
|
}
|