@apifuse/provider-sdk 2.2.0-beta.3 → 2.2.0-beta.4
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 +14 -0
- package/CHANGELOG.md +4 -0
- package/bin/apifuse-check.ts +18 -58
- package/bin/apifuse-create.ts +1 -1
- package/bin/apifuse-dev.ts +27 -52
- package/bin/apifuse-pack-smoke.ts +22 -81
- package/bin/apifuse-pack-types.ts +266 -0
- package/bin/apifuse-perf.ts +45 -127
- package/bin/apifuse-record.ts +23 -61
- package/bin/apifuse-submit-check.ts +26 -21
- package/bin/apifuse.ts +1 -1
- package/bin/submit-check-xml.ts +1 -1
- package/dist/auth-turn/index.d.ts +1 -1
- package/dist/auth.d.ts +2 -2
- package/dist/auth.js +9 -18
- package/dist/ceremonies/index.d.ts +1 -1
- package/dist/ceremonies/index.js +8 -18
- package/dist/config/loader.d.ts +2 -2
- package/dist/config/loader.js +19 -42
- package/dist/contract-serialization.d.ts +2 -2
- package/dist/contract-serialization.js +3 -6
- package/dist/contract-types.d.ts +2 -2
- package/dist/contract.d.ts +3 -3
- package/dist/contract.js +4 -6
- package/dist/define.d.ts +8 -1
- package/dist/define.js +57 -115
- package/dist/dev.d.ts +1 -1
- package/dist/dev.js +1 -1
- package/dist/errors.d.ts +1 -1
- package/dist/errors.js +1 -3
- 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 +43 -42
- package/dist/index.js +38 -37
- package/dist/lint.js +8 -15
- package/dist/provider.d.ts +11 -11
- package/dist/provider.js +9 -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 +1 -1
- package/dist/runtime/auth-flow.js +3 -3
- package/dist/runtime/browser.d.ts +1 -1
- package/dist/runtime/browser.js +15 -29
- package/dist/runtime/cache.d.ts +1 -1
- package/dist/runtime/cache.js +4 -8
- package/dist/runtime/choice.d.ts +1 -1
- package/dist/runtime/choice.js +12 -34
- 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 +2 -2
- package/dist/runtime/http.d.ts +2 -2
- package/dist/runtime/http.js +5 -5
- 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 +5 -15
- package/dist/runtime/keyring.js +1 -1
- package/dist/runtime/namespace.js +1 -1
- 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 +3 -5
- 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 +1 -1
- package/dist/runtime/proxy-telemetry.js +16 -48
- package/dist/runtime/redis.d.ts +1 -1
- package/dist/runtime/redis.js +2 -4
- package/dist/runtime/request-options.d.ts +1 -1
- package/dist/runtime/state.d.ts +2 -2
- package/dist/runtime/state.js +3 -3
- package/dist/runtime/stealth.d.ts +2 -2
- package/dist/runtime/stealth.js +6 -6
- package/dist/runtime/stt.d.ts +1 -1
- package/dist/runtime/stt.js +11 -15
- 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-redaction.d.ts +1 -1
- package/dist/server/self-test-redaction.js +1 -1
- package/dist/server/self-test.d.ts +3 -3
- package/dist/server/self-test.js +3 -3
- package/dist/server/serve.d.ts +3 -3
- package/dist/server/serve.js +36 -49
- package/dist/server/types.js +2 -7
- package/dist/stealth/profiles.d.ts +1 -1
- package/dist/stealth/profiles.js +5 -14
- package/dist/stream.d.ts +1 -1
- package/dist/testing/index.d.ts +2 -2
- package/dist/testing/index.js +2 -2
- package/dist/testing/run.d.ts +1 -1
- package/dist/testing/run.js +7 -14
- package/dist/types.d.ts +57 -0
- package/dist/user-input.d.ts +30 -0
- package/dist/user-input.js +66 -0
- package/package.json +6 -4
- package/src/auth-turn/index.ts +1 -1
- package/src/auth.ts +28 -86
- package/src/ceremonies/index.ts +24 -78
- package/src/config/loader.ts +58 -176
- package/src/contract-serialization.ts +5 -11
- package/src/contract-types.ts +2 -2
- package/src/contract.ts +12 -28
- package/src/define.ts +174 -495
- package/src/dev.ts +4 -9
- package/src/errors.ts +4 -11
- 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 +44 -42
- package/src/lint.ts +89 -159
- package/src/provider.ts +12 -11
- package/src/public-schema-field-lint.ts +7 -33
- package/src/recipes/gov-api.ts +2 -5
- package/src/runtime/auth-flow.ts +5 -7
- package/src/runtime/browser.ts +64 -187
- package/src/runtime/cache.ts +20 -67
- package/src/runtime/choice.ts +55 -129
- package/src/runtime/credential.ts +2 -2
- package/src/runtime/env.ts +1 -1
- package/src/runtime/executor.ts +9 -19
- package/src/runtime/http.ts +7 -7
- package/src/runtime/insights.ts +15 -53
- package/src/runtime/instrumentation.ts +19 -58
- package/src/runtime/keyring.ts +7 -19
- package/src/runtime/namespace.ts +2 -7
- 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 +17 -38
- package/src/runtime/proxy-retry-policy.ts +3 -3
- package/src/runtime/proxy-telemetry.ts +23 -72
- package/src/runtime/redis.ts +4 -12
- package/src/runtime/request-options.ts +4 -13
- package/src/runtime/state.ts +30 -109
- package/src/runtime/stealth.ts +8 -8
- package/src/runtime/stt.ts +38 -94
- package/src/runtime/trace.ts +14 -44
- package/src/runtime/waterfall.ts +5 -18
- package/src/schema.ts +23 -84
- package/src/serve.ts +1 -1
- package/src/server/index.ts +7 -7
- package/src/server/self-test-redaction.ts +2 -2
- package/src/server/self-test.ts +5 -5
- package/src/server/serve.ts +87 -242
- package/src/server/types.ts +6 -19
- package/src/stealth/profiles.ts +10 -26
- package/src/stream.ts +8 -19
- package/src/testing/index.ts +2 -2
- package/src/testing/run.ts +19 -67
- package/src/types.ts +58 -0
- package/src/user-input.ts +118 -0
package/dist/schema.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { ValidationError } from "./errors";
|
|
3
|
-
import { providerLocaleKey } from "./i18n/keys";
|
|
2
|
+
import { ValidationError } from "./errors.js";
|
|
3
|
+
import { providerLocaleKey } from "./i18n/keys.js";
|
|
4
4
|
export { z };
|
|
5
5
|
function isFailureResult(result) {
|
|
6
6
|
return "issues" in result;
|
|
@@ -99,21 +99,15 @@ export function field(schema, options = {}) {
|
|
|
99
99
|
const metadata = described.meta() ?? {};
|
|
100
100
|
return described.meta({
|
|
101
101
|
...metadata,
|
|
102
|
-
...((options.sensitive ?? true)
|
|
103
|
-
|
|
104
|
-
: {}),
|
|
105
|
-
...(options.kind
|
|
106
|
-
? { [APIFUSE_SENSITIVE_KIND_META_KEY]: options.kind }
|
|
107
|
-
: {}),
|
|
102
|
+
...((options.sensitive ?? true) ? { [APIFUSE_SENSITIVE_META_KEY]: true } : {}),
|
|
103
|
+
...(options.kind ? { [APIFUSE_SENSITIVE_KIND_META_KEY]: options.kind } : {}),
|
|
108
104
|
});
|
|
109
105
|
}
|
|
110
106
|
export function sensitive(schema, kind) {
|
|
111
107
|
return field(schema, { sensitive: true, kind });
|
|
112
108
|
}
|
|
113
109
|
function sensitiveString(kind, description, options = {}) {
|
|
114
|
-
const schema = options.minLength === undefined
|
|
115
|
-
? z.string()
|
|
116
|
-
: z.string().min(options.minLength);
|
|
110
|
+
const schema = options.minLength === undefined ? z.string() : z.string().min(options.minLength);
|
|
117
111
|
return field(schema, {
|
|
118
112
|
kind,
|
|
119
113
|
description: options.description ?? description,
|
|
@@ -132,8 +126,7 @@ export const fields = {
|
|
|
132
126
|
};
|
|
133
127
|
export function isSensitiveSchema(schema) {
|
|
134
128
|
const metadata = readZodMetadata(schema);
|
|
135
|
-
return
|
|
136
|
-
Reflect.get(metadata, APIFUSE_SENSITIVE_META_KEY) === true);
|
|
129
|
+
return metadata !== undefined && Reflect.get(metadata, APIFUSE_SENSITIVE_META_KEY) === true;
|
|
137
130
|
}
|
|
138
131
|
export function collectSensitivePaths(schema) {
|
|
139
132
|
const out = [];
|
|
@@ -217,8 +210,7 @@ function pathMatches(path, patterns) {
|
|
|
217
210
|
}
|
|
218
211
|
function isReservedSensitiveKey(key) {
|
|
219
212
|
const normalized = key.toLowerCase().replace(/[-_\s]/g, "");
|
|
220
|
-
return
|
|
221
|
-
RESERVED_SENSITIVE_KEYS.has(key.toLowerCase()));
|
|
213
|
+
return RESERVED_SENSITIVE_KEYS.has(normalized) || RESERVED_SENSITIVE_KEYS.has(key.toLowerCase());
|
|
222
214
|
}
|
|
223
215
|
function readZodMetadata(schema) {
|
|
224
216
|
if (!schema || typeof schema !== "object" || !("meta" in schema)) {
|
package/dist/serve.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { createServerApp, type ServeOptions, serve } from "./server/serve";
|
|
1
|
+
export { createServerApp, type ServeOptions, serve } from "./server/serve.js";
|
package/dist/serve.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { createServerApp, serve } from "./server/serve";
|
|
1
|
+
export { createServerApp, serve } from "./server/serve.js";
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export { createServerApp, type ServeOptions, serve } from "./serve";
|
|
2
|
-
export { computeSelfTestPlanDigest, createSelfTestApp, createSelfTestInvoke, DEFAULT_SELF_TEST_REQUEST_BUDGET_MS, isSelfTestReadOnlyOperation, PROVIDER_RUNTIME_SELF_TEST_REQUEST_BUDGET_MS_ENV, resolveSelfTestPort, SELF_TEST_HEALTHZ_PATH, SELF_TEST_PATH, SELF_TEST_SCHEMA_VERSION, type SelfTestAppOptions, type SelfTestCaseResult, type SelfTestCaseStatus, type SelfTestOperationInvoke, type SelfTestRequest, SelfTestRequestSchema, type SelfTestResponse, } from "./self-test";
|
|
3
|
-
export { resolveHealthCheckInputDateTokens } from "./self-test-input-tokens";
|
|
4
|
-
export { collectSelfTestSensitiveValues, redactSelfTestText, SELF_TEST_MAX_TEXT_LENGTH, SELF_TEST_REDACTED_PLACEHOLDER, } from "./self-test-redaction";
|
|
5
|
-
export { DEFAULT_SELF_TEST_PORT, deriveSelfTestToken, PROVIDER_RUNTIME_SELF_TEST_MASTER_SECRET_ENV, PROVIDER_RUNTIME_SELF_TEST_MASTER_SECRET_PREVIOUS_ENV, PROVIDER_RUNTIME_SELF_TEST_PORT_ENV, resolveSelfTestMasterSecrets, type SelfTestMasterSecrets, verifySelfTestAuthorization, } from "./self-test-token";
|
|
6
|
-
export type { AuthFlowRequest, AuthFlowResponse, AuthFlowSuccessResponse, ConnectionMode, OperationConnection, OperationErrorResponse, OperationRequest, OperationResponse, OperationSuccessResponse, } from "./types";
|
|
7
|
-
export { AuthFlowRequestSchema, AuthFlowSuccessResponseSchema, ConnectionModeSchema, ErrorEnvelopeSchema, OperationConnectionSchema, OperationErrorResponseSchema, OperationRequestSchema, OperationSuccessResponseSchema, } from "./types";
|
|
1
|
+
export { createServerApp, type ServeOptions, serve } from "./serve.js";
|
|
2
|
+
export { computeSelfTestPlanDigest, createSelfTestApp, createSelfTestInvoke, DEFAULT_SELF_TEST_REQUEST_BUDGET_MS, isSelfTestReadOnlyOperation, PROVIDER_RUNTIME_SELF_TEST_REQUEST_BUDGET_MS_ENV, resolveSelfTestPort, SELF_TEST_HEALTHZ_PATH, SELF_TEST_PATH, SELF_TEST_SCHEMA_VERSION, type SelfTestAppOptions, type SelfTestCaseResult, type SelfTestCaseStatus, type SelfTestOperationInvoke, type SelfTestRequest, SelfTestRequestSchema, type SelfTestResponse, } from "./self-test.js";
|
|
3
|
+
export { resolveHealthCheckInputDateTokens } from "./self-test-input-tokens.js";
|
|
4
|
+
export { collectSelfTestSensitiveValues, redactSelfTestText, SELF_TEST_MAX_TEXT_LENGTH, SELF_TEST_REDACTED_PLACEHOLDER, } from "./self-test-redaction.js";
|
|
5
|
+
export { DEFAULT_SELF_TEST_PORT, deriveSelfTestToken, PROVIDER_RUNTIME_SELF_TEST_MASTER_SECRET_ENV, PROVIDER_RUNTIME_SELF_TEST_MASTER_SECRET_PREVIOUS_ENV, PROVIDER_RUNTIME_SELF_TEST_PORT_ENV, resolveSelfTestMasterSecrets, type SelfTestMasterSecrets, verifySelfTestAuthorization, } from "./self-test-token.js";
|
|
6
|
+
export type { AuthFlowRequest, AuthFlowResponse, AuthFlowSuccessResponse, ConnectionMode, OperationConnection, OperationErrorResponse, OperationRequest, OperationResponse, OperationSuccessResponse, } from "./types.js";
|
|
7
|
+
export { AuthFlowRequestSchema, AuthFlowSuccessResponseSchema, ConnectionModeSchema, ErrorEnvelopeSchema, OperationConnectionSchema, OperationErrorResponseSchema, OperationRequestSchema, OperationSuccessResponseSchema, } from "./types.js";
|
package/dist/server/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { createServerApp, serve } from "./serve";
|
|
2
|
-
export { computeSelfTestPlanDigest, createSelfTestApp, createSelfTestInvoke, DEFAULT_SELF_TEST_REQUEST_BUDGET_MS, isSelfTestReadOnlyOperation, PROVIDER_RUNTIME_SELF_TEST_REQUEST_BUDGET_MS_ENV, resolveSelfTestPort, SELF_TEST_HEALTHZ_PATH, SELF_TEST_PATH, SELF_TEST_SCHEMA_VERSION, SelfTestRequestSchema, } from "./self-test";
|
|
3
|
-
export { resolveHealthCheckInputDateTokens } from "./self-test-input-tokens";
|
|
4
|
-
export { collectSelfTestSensitiveValues, redactSelfTestText, SELF_TEST_MAX_TEXT_LENGTH, SELF_TEST_REDACTED_PLACEHOLDER, } from "./self-test-redaction";
|
|
5
|
-
export { DEFAULT_SELF_TEST_PORT, deriveSelfTestToken, PROVIDER_RUNTIME_SELF_TEST_MASTER_SECRET_ENV, PROVIDER_RUNTIME_SELF_TEST_MASTER_SECRET_PREVIOUS_ENV, PROVIDER_RUNTIME_SELF_TEST_PORT_ENV, resolveSelfTestMasterSecrets, verifySelfTestAuthorization, } from "./self-test-token";
|
|
6
|
-
export { AuthFlowRequestSchema, AuthFlowSuccessResponseSchema, ConnectionModeSchema, ErrorEnvelopeSchema, OperationConnectionSchema, OperationErrorResponseSchema, OperationRequestSchema, OperationSuccessResponseSchema, } from "./types";
|
|
1
|
+
export { createServerApp, serve } from "./serve.js";
|
|
2
|
+
export { computeSelfTestPlanDigest, createSelfTestApp, createSelfTestInvoke, DEFAULT_SELF_TEST_REQUEST_BUDGET_MS, isSelfTestReadOnlyOperation, PROVIDER_RUNTIME_SELF_TEST_REQUEST_BUDGET_MS_ENV, resolveSelfTestPort, SELF_TEST_HEALTHZ_PATH, SELF_TEST_PATH, SELF_TEST_SCHEMA_VERSION, SelfTestRequestSchema, } from "./self-test.js";
|
|
3
|
+
export { resolveHealthCheckInputDateTokens } from "./self-test-input-tokens.js";
|
|
4
|
+
export { collectSelfTestSensitiveValues, redactSelfTestText, SELF_TEST_MAX_TEXT_LENGTH, SELF_TEST_REDACTED_PLACEHOLDER, } from "./self-test-redaction.js";
|
|
5
|
+
export { DEFAULT_SELF_TEST_PORT, deriveSelfTestToken, PROVIDER_RUNTIME_SELF_TEST_MASTER_SECRET_ENV, PROVIDER_RUNTIME_SELF_TEST_MASTER_SECRET_PREVIOUS_ENV, PROVIDER_RUNTIME_SELF_TEST_PORT_ENV, resolveSelfTestMasterSecrets, verifySelfTestAuthorization, } from "./self-test-token.js";
|
|
6
|
+
export { AuthFlowRequestSchema, AuthFlowSuccessResponseSchema, ConnectionModeSchema, ErrorEnvelopeSchema, OperationConnectionSchema, OperationErrorResponseSchema, OperationRequestSchema, OperationSuccessResponseSchema, } from "./types.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ProviderDefinition } from "../types";
|
|
1
|
+
import type { ProviderDefinition } from "../types.js";
|
|
2
2
|
export declare const SELF_TEST_REDACTED_PLACEHOLDER = "[REDACTED]";
|
|
3
3
|
/** Maximum length of any string echoed in a self-test response. */
|
|
4
4
|
export declare const SELF_TEST_MAX_TEXT_LENGTH = 300;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PROVIDER_RUNTIME_SELF_TEST_MASTER_SECRET_ENV, PROVIDER_RUNTIME_SELF_TEST_MASTER_SECRET_PREVIOUS_ENV, } from "./self-test-token";
|
|
1
|
+
import { PROVIDER_RUNTIME_SELF_TEST_MASTER_SECRET_ENV, PROVIDER_RUNTIME_SELF_TEST_MASTER_SECRET_PREVIOUS_ENV, } from "./self-test-token.js";
|
|
2
2
|
export const SELF_TEST_REDACTED_PLACEHOLDER = "[REDACTED]";
|
|
3
3
|
/** Maximum length of any string echoed in a self-test response. */
|
|
4
4
|
export const SELF_TEST_MAX_TEXT_LENGTH = 300;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import type { OperationDefinition, ProviderDefinition } from "../types";
|
|
4
|
-
import { type SelfTestMasterSecrets } from "./self-test-token";
|
|
5
|
-
import type { OperationConnection } from "./types";
|
|
3
|
+
import type { OperationDefinition, ProviderDefinition } from "../types.js";
|
|
4
|
+
import { type SelfTestMasterSecrets } from "./self-test-token.js";
|
|
5
|
+
import type { OperationConnection } from "./types.js";
|
|
6
6
|
export declare const SELF_TEST_SCHEMA_VERSION: 1;
|
|
7
7
|
export declare const SELF_TEST_PATH = "/internal/health/self-test";
|
|
8
8
|
export declare const SELF_TEST_HEALTHZ_PATH = "/healthz";
|
package/dist/server/self-test.js
CHANGED
|
@@ -2,9 +2,9 @@ import { createHash, randomUUID } from "node:crypto";
|
|
|
2
2
|
import { readFileSync } from "node:fs";
|
|
3
3
|
import { Hono } from "hono";
|
|
4
4
|
import { z } from "zod";
|
|
5
|
-
import { resolveHealthCheckInputDateTokens } from "./self-test-input-tokens";
|
|
6
|
-
import { collectSelfTestSensitiveValues, redactSelfTestText } from "./self-test-redaction";
|
|
7
|
-
import { DEFAULT_SELF_TEST_PORT, PROVIDER_RUNTIME_SELF_TEST_PORT_ENV, verifySelfTestAuthorization, } from "./self-test-token";
|
|
5
|
+
import { resolveHealthCheckInputDateTokens } from "./self-test-input-tokens.js";
|
|
6
|
+
import { collectSelfTestSensitiveValues, redactSelfTestText } from "./self-test-redaction.js";
|
|
7
|
+
import { DEFAULT_SELF_TEST_PORT, PROVIDER_RUNTIME_SELF_TEST_PORT_ENV, verifySelfTestAuthorization, } from "./self-test-token.js";
|
|
8
8
|
export const SELF_TEST_SCHEMA_VERSION = 1;
|
|
9
9
|
export const SELF_TEST_PATH = "/internal/health/self-test";
|
|
10
10
|
export const SELF_TEST_HEALTHZ_PATH = "/healthz";
|
package/dist/server/serve.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
|
-
import { type ProviderErrorCategory } from "../observability";
|
|
3
|
-
import type { ProviderDefinition, ProviderRuntimeState, SttContext } from "../types";
|
|
4
|
-
import { type OperationRequest } from "./types";
|
|
2
|
+
import { type ProviderErrorCategory } from "../observability.js";
|
|
3
|
+
import type { ProviderDefinition, ProviderRuntimeState, SttContext } from "../types.js";
|
|
4
|
+
import { type OperationRequest } from "./types.js";
|
|
5
5
|
export declare function resolveProviderProxyAffinityKey(provider: ProviderDefinition, request: OperationRequest, operationId: string): string;
|
|
6
6
|
type ProviderRequestCost = {
|
|
7
7
|
durationMs: number;
|
package/dist/server/serve.js
CHANGED
|
@@ -2,32 +2,32 @@ import { existsSync } from "node:fs";
|
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { Hono } from "hono";
|
|
4
4
|
import { z } from "zod";
|
|
5
|
-
import { AuthAbortError, createAuthFlowHelpers } from "../auth";
|
|
6
|
-
import { AuthError, isProviderError, isSessionExpiredError, isTransportError, ProviderError, } from "../errors";
|
|
7
|
-
import { loadProviderLocaleCatalogs, localizeAuthTurn, } from "../i18n/catalog";
|
|
8
|
-
import { categoryForStatus, isRetryableCategory, PROVIDER_OBSERVABILITY_TAXONOMY_VERSION, } from "../observability";
|
|
9
|
-
import { createScratchpad } from "../runtime/auth-flow";
|
|
10
|
-
import { createBrowserClient } from "../runtime/browser";
|
|
11
|
-
import { createProviderCache } from "../runtime/cache";
|
|
12
|
-
import { createProviderChoiceContext, PROVIDER_RUNTIME_CHOICE_TOKEN_MASTER_SECRET_ENV, } from "../runtime/choice";
|
|
13
|
-
import { createCredentialContext } from "../runtime/credential";
|
|
14
|
-
import { createEnvContext } from "../runtime/env";
|
|
15
|
-
import { executeOperation } from "../runtime/executor";
|
|
16
|
-
import { createHttpClient } from "../runtime/http";
|
|
17
|
-
import { wrapWithInstrumentation } from "../runtime/instrumentation";
|
|
18
|
-
import { getProviderBaseUrl } from "../runtime/provider";
|
|
19
|
-
import { PROXY_AUTH_IP_DENIED_CODE, PROXY_EDGE_AUTH_REJECTED_CODE, PROXY_POOL_EXHAUSTED_CODE, } from "../runtime/proxy-errors";
|
|
20
|
-
import { PROVIDER_TELEMETRY_HEADER, ProxyTelemetryCollector
|
|
21
|
-
import { createProviderRuntimeStateFromEnv, createUnsupportedProviderRuntimeState, } from "../runtime/state";
|
|
22
|
-
import { createStealthClient } from "../runtime/stealth";
|
|
23
|
-
import { createSttClientFromEnv } from "../runtime/stt";
|
|
24
|
-
import { createTraceContext } from "../runtime/trace";
|
|
25
|
-
import { parseSchema } from "../schema";
|
|
26
|
-
import { getStealthProfile } from "../stealth/profiles";
|
|
27
|
-
import { APIFUSE_STREAM_DONE_EVENT, APIFUSE_STREAM_ERROR_EVENT, encodeSseEvent, error as streamError, } from "../stream";
|
|
28
|
-
import { createSelfTestApp, createSelfTestInvoke, resolveSelfTestPort
|
|
29
|
-
import { resolveSelfTestMasterSecrets } from "./self-test-token";
|
|
30
|
-
import { AuthFlowRequestSchema, OperationRequestSchema, } from "./types";
|
|
5
|
+
import { AuthAbortError, createAuthFlowHelpers } from "../auth.js";
|
|
6
|
+
import { AuthError, isProviderError, isSessionExpiredError, isTransportError, ProviderError, } from "../errors.js";
|
|
7
|
+
import { loadProviderLocaleCatalogs, localizeAuthTurn, } from "../i18n/catalog.js";
|
|
8
|
+
import { categoryForStatus, isRetryableCategory, PROVIDER_OBSERVABILITY_TAXONOMY_VERSION, } from "../observability.js";
|
|
9
|
+
import { createScratchpad } from "../runtime/auth-flow.js";
|
|
10
|
+
import { createBrowserClient } from "../runtime/browser.js";
|
|
11
|
+
import { createProviderCache } from "../runtime/cache.js";
|
|
12
|
+
import { createProviderChoiceContext, PROVIDER_RUNTIME_CHOICE_TOKEN_MASTER_SECRET_ENV, } from "../runtime/choice.js";
|
|
13
|
+
import { createCredentialContext } from "../runtime/credential.js";
|
|
14
|
+
import { createEnvContext } from "../runtime/env.js";
|
|
15
|
+
import { executeOperation } from "../runtime/executor.js";
|
|
16
|
+
import { createHttpClient } from "../runtime/http.js";
|
|
17
|
+
import { wrapWithInstrumentation } from "../runtime/instrumentation.js";
|
|
18
|
+
import { getProviderBaseUrl } from "../runtime/provider.js";
|
|
19
|
+
import { PROXY_AUTH_IP_DENIED_CODE, PROXY_EDGE_AUTH_REJECTED_CODE, PROXY_POOL_EXHAUSTED_CODE, } from "../runtime/proxy-errors.js";
|
|
20
|
+
import { PROVIDER_TELEMETRY_HEADER, ProxyTelemetryCollector } from "../runtime/proxy-telemetry.js";
|
|
21
|
+
import { createProviderRuntimeStateFromEnv, createUnsupportedProviderRuntimeState, } from "../runtime/state.js";
|
|
22
|
+
import { createStealthClient } from "../runtime/stealth.js";
|
|
23
|
+
import { createSttClientFromEnv } from "../runtime/stt.js";
|
|
24
|
+
import { createTraceContext } from "../runtime/trace.js";
|
|
25
|
+
import { parseSchema } from "../schema.js";
|
|
26
|
+
import { getStealthProfile } from "../stealth/profiles.js";
|
|
27
|
+
import { APIFUSE_STREAM_DONE_EVENT, APIFUSE_STREAM_ERROR_EVENT, encodeSseEvent, error as streamError, } from "../stream.js";
|
|
28
|
+
import { createSelfTestApp, createSelfTestInvoke, resolveSelfTestPort } from "./self-test.js";
|
|
29
|
+
import { resolveSelfTestMasterSecrets } from "./self-test-token.js";
|
|
30
|
+
import { AuthFlowRequestSchema, OperationRequestSchema, } from "./types.js";
|
|
31
31
|
const DEFAULT_HOST = "0.0.0.0";
|
|
32
32
|
const DEFAULT_PORT = 3000;
|
|
33
33
|
const AUTH_FLOW_LOCALES = ["en", "ko", "ja"];
|
|
@@ -93,9 +93,7 @@ function getProviderStealthBaseUrl(provider) {
|
|
|
93
93
|
return firstHost ? `https://${firstHost}` : undefined;
|
|
94
94
|
}
|
|
95
95
|
function getProviderStealthProfile(provider) {
|
|
96
|
-
return provider.stealth?.profile
|
|
97
|
-
? getStealthProfile(provider.stealth.profile)
|
|
98
|
-
: undefined;
|
|
96
|
+
return provider.stealth?.profile ? getStealthProfile(provider.stealth.profile) : undefined;
|
|
99
97
|
}
|
|
100
98
|
function isProductionProviderBrowserMode(provider, env = process.env) {
|
|
101
99
|
if (provider.runtime !== "browser") {
|
|
@@ -104,13 +102,11 @@ function isProductionProviderBrowserMode(provider, env = process.env) {
|
|
|
104
102
|
if (env.APIFUSE__PROVIDER__RUNTIME === "browser") {
|
|
105
103
|
return true;
|
|
106
104
|
}
|
|
107
|
-
return
|
|
105
|
+
return env.NODE_ENV === "production" && env.APIFUSE__PROVIDER__ID === provider.id;
|
|
108
106
|
}
|
|
109
107
|
export function resolveProviderProxyAffinityKey(provider, request, operationId) {
|
|
110
108
|
const connectionKey = resolveOperationConnectionId(request) ?? request.connection?.externalRef;
|
|
111
|
-
const affinity = typeof provider.proxy === "object"
|
|
112
|
-
? provider.proxy.session?.affinity
|
|
113
|
-
: undefined;
|
|
109
|
+
const affinity = typeof provider.proxy === "object" ? provider.proxy.session?.affinity : undefined;
|
|
114
110
|
if (affinity === "operation") {
|
|
115
111
|
return `${provider.id}/${operationId}`;
|
|
116
112
|
}
|
|
@@ -460,9 +456,7 @@ function logProviderError(logger, provider, kind, route, requestId, error, statu
|
|
|
460
456
|
: "internal_error";
|
|
461
457
|
const errorClass = error instanceof Error ? error.name : typeof error;
|
|
462
458
|
const message = error instanceof Error ? error.message : String(error);
|
|
463
|
-
const details = isProviderError(error)
|
|
464
|
-
? providerObservabilityDetails(error)
|
|
465
|
-
: undefined;
|
|
459
|
+
const details = isProviderError(error) ? providerObservabilityDetails(error) : undefined;
|
|
466
460
|
const emit = typeof logger === "function" ? logger : defaultProviderServerLogger;
|
|
467
461
|
emit({
|
|
468
462
|
level: status >= 500 ? "error" : "warn",
|
|
@@ -599,8 +593,7 @@ async function validateSseEvent(operation, event) {
|
|
|
599
593
|
const transport = getSseTransport(operation);
|
|
600
594
|
const schema = transport?.events?.[event.event];
|
|
601
595
|
if (!schema) {
|
|
602
|
-
if (event.event === APIFUSE_STREAM_ERROR_EVENT ||
|
|
603
|
-
event.event === APIFUSE_STREAM_DONE_EVENT) {
|
|
596
|
+
if (event.event === APIFUSE_STREAM_ERROR_EVENT || event.event === APIFUSE_STREAM_DONE_EVENT) {
|
|
604
597
|
return event;
|
|
605
598
|
}
|
|
606
599
|
throw new ProviderError(`SSE event "${event.event}" is not declared in operation transport.events.`, {
|
|
@@ -719,8 +712,7 @@ function enforceStreamChunkLimit(body, maxChunkBytes) {
|
|
|
719
712
|
}
|
|
720
713
|
function toStreamingResponse(operation, result, cleanup, requestId) {
|
|
721
714
|
const transport = operation.transport?.kind ?? "json";
|
|
722
|
-
if (transport === "sse" &&
|
|
723
|
-
(result instanceof Response || result instanceof ReadableStream)) {
|
|
715
|
+
if (transport === "sse" && (result instanceof Response || result instanceof ReadableStream)) {
|
|
724
716
|
void cleanup();
|
|
725
717
|
throw new ProviderError("SSE operations must return an AsyncIterable of typed stream.event(...) values.", {
|
|
726
718
|
code: "SSE_RESULT_UNSUPPORTED",
|
|
@@ -731,9 +723,7 @@ function toStreamingResponse(operation, result, cleanup, requestId) {
|
|
|
731
723
|
}
|
|
732
724
|
if (result instanceof Response) {
|
|
733
725
|
const httpTransport = getHttpStreamTransport(operation);
|
|
734
|
-
if (httpTransport &&
|
|
735
|
-
result.body &&
|
|
736
|
-
httpTransport?.maxChunkBytes !== undefined) {
|
|
726
|
+
if (httpTransport && result.body && httpTransport?.maxChunkBytes !== undefined) {
|
|
737
727
|
return responseWithCleanup(new Response(enforceStreamChunkLimit(result.body, httpTransport.maxChunkBytes), {
|
|
738
728
|
headers: result.headers,
|
|
739
729
|
status: result.status,
|
|
@@ -752,8 +742,7 @@ function toStreamingResponse(operation, result, cleanup, requestId) {
|
|
|
752
742
|
? { "Content-Type": "text/event-stream; charset=utf-8" }
|
|
753
743
|
: {
|
|
754
744
|
"Content-Type": operation.transport?.kind === "http-stream"
|
|
755
|
-
? (operation.transport.contentType ??
|
|
756
|
-
"application/octet-stream")
|
|
745
|
+
? (operation.transport.contentType ?? "application/octet-stream")
|
|
757
746
|
: "application/octet-stream",
|
|
758
747
|
},
|
|
759
748
|
}), cleanup);
|
|
@@ -771,9 +760,7 @@ function getSseTransport(operation) {
|
|
|
771
760
|
return operation.transport?.kind === "sse" ? operation.transport : undefined;
|
|
772
761
|
}
|
|
773
762
|
function getHttpStreamTransport(operation) {
|
|
774
|
-
return operation.transport?.kind === "http-stream"
|
|
775
|
-
? operation.transport
|
|
776
|
-
: undefined;
|
|
763
|
+
return operation.transport?.kind === "http-stream" ? operation.transport : undefined;
|
|
777
764
|
}
|
|
778
765
|
function toAuthFlowResponse(result, contextPatch) {
|
|
779
766
|
if (result instanceof Response) {
|
|
@@ -801,7 +788,7 @@ function isAuthFlowLocale(value) {
|
|
|
801
788
|
return value === "en" || value === "ko" || value === "ja";
|
|
802
789
|
}
|
|
803
790
|
function isAuthTurn(value) {
|
|
804
|
-
return
|
|
791
|
+
return !!value && typeof value === "object" && "kind" in value && "turnId" in value;
|
|
805
792
|
}
|
|
806
793
|
function loadAuthFlowLocaleCatalogs(provider) {
|
|
807
794
|
for (const providerDir of [
|
package/dist/server/types.js
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { HttpRetryPreset } from "../types";
|
|
3
|
-
export const ConnectionModeSchema = z.enum([
|
|
4
|
-
"oauth2",
|
|
5
|
-
"credentials",
|
|
6
|
-
"platform-managed",
|
|
7
|
-
"none",
|
|
8
|
-
]);
|
|
2
|
+
import { HttpRetryPreset } from "../types.js";
|
|
3
|
+
export const ConnectionModeSchema = z.enum(["oauth2", "credentials", "platform-managed", "none"]);
|
|
9
4
|
export const OperationConnectionSchema = z.object({
|
|
10
5
|
id: z.string(),
|
|
11
6
|
mode: ConnectionModeSchema,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { StealthProfile } from "../types";
|
|
1
|
+
import type { StealthProfile } from "../types.js";
|
|
2
2
|
export declare function generateLayer2Headers(profile: StealthProfile): Record<string, string>;
|
|
3
3
|
export declare function getStealthProfile(name: string): StealthProfile;
|
|
4
4
|
export declare function listStealthProfiles(): string[];
|
package/dist/stealth/profiles.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SDKError } from "../errors";
|
|
1
|
+
import { SDKError } from "../errors.js";
|
|
2
2
|
const CHROMIUM_HEADER_ORDER = [
|
|
3
3
|
":method",
|
|
4
4
|
":authority",
|
|
@@ -74,12 +74,8 @@ function createProfile(name, definition) {
|
|
|
74
74
|
tlsClientIdentifier: definition.tlsClientIdentifier,
|
|
75
75
|
ja3: definition.ja3,
|
|
76
76
|
ja4: definition.ja4,
|
|
77
|
-
h2Settings: definition.h2Settings
|
|
78
|
-
|
|
79
|
-
: undefined,
|
|
80
|
-
headerOrder: definition.headerOrder
|
|
81
|
-
? [...definition.headerOrder]
|
|
82
|
-
: undefined,
|
|
77
|
+
h2Settings: definition.h2Settings ? { ...definition.h2Settings } : undefined,
|
|
78
|
+
headerOrder: definition.headerOrder ? [...definition.headerOrder] : undefined,
|
|
83
79
|
};
|
|
84
80
|
}
|
|
85
81
|
function extractBrowserMajorVersion(profile) {
|
|
@@ -120,9 +116,7 @@ export function generateLayer2Headers(profile) {
|
|
|
120
116
|
: `"Chromium";v="${majorVersion}", "Google Chrome";v="${majorVersion}", "Not)A;Brand";v="99"`;
|
|
121
117
|
headers["Sec-Ch-Ua-Platform"] = toPlatformHeaderValue(profile.platform);
|
|
122
118
|
headers["Sec-Ch-Ua-Mobile"] =
|
|
123
|
-
profile.platform === "android" || profile.platform === "ios"
|
|
124
|
-
? "?1"
|
|
125
|
-
: "?0";
|
|
119
|
+
profile.platform === "android" || profile.platform === "ios" ? "?1" : "?0";
|
|
126
120
|
}
|
|
127
121
|
return headers;
|
|
128
122
|
}
|
|
@@ -252,8 +246,5 @@ export function getStealthProfile(name) {
|
|
|
252
246
|
};
|
|
253
247
|
}
|
|
254
248
|
export function listStealthProfiles() {
|
|
255
|
-
return [
|
|
256
|
-
...Object.keys(STEALTH_PROFILES),
|
|
257
|
-
...Object.keys(STEALTH_PROFILE_ALIASES),
|
|
258
|
-
];
|
|
249
|
+
return [...Object.keys(STEALTH_PROFILES), ...Object.keys(STEALTH_PROFILE_ALIASES)];
|
|
259
250
|
}
|
package/dist/stream.d.ts
CHANGED
package/dist/testing/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { describeTransform, snapshotTransform, toMatchShape } from "./helpers";
|
|
2
|
-
export { runStandardTests } from "./run";
|
|
1
|
+
export { describeTransform, snapshotTransform, toMatchShape } from "./helpers.js";
|
|
2
|
+
export { runStandardTests } from "./run.js";
|
package/dist/testing/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { describeTransform, snapshotTransform, toMatchShape } from "./helpers";
|
|
2
|
-
export { runStandardTests } from "./run";
|
|
1
|
+
export { describeTransform, snapshotTransform, toMatchShape } from "./helpers.js";
|
|
2
|
+
export { runStandardTests } from "./run.js";
|
package/dist/testing/run.d.ts
CHANGED
package/dist/testing/run.js
CHANGED
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
import { describe, expect, it } from "bun:test";
|
|
2
|
-
import { createProviderCache } from "../runtime/cache";
|
|
3
|
-
import { createTestProviderChoiceContext } from "../runtime/choice";
|
|
4
|
-
import { createMemoryProviderRuntimeState } from "../runtime/state";
|
|
5
|
-
import { createUnsupportedSttClient } from "../runtime/stt";
|
|
6
|
-
import { safeParseSchemaSync } from "../schema";
|
|
2
|
+
import { createProviderCache } from "../runtime/cache.js";
|
|
3
|
+
import { createTestProviderChoiceContext } from "../runtime/choice.js";
|
|
4
|
+
import { createMemoryProviderRuntimeState } from "../runtime/state.js";
|
|
5
|
+
import { createUnsupportedSttClient } from "../runtime/stt.js";
|
|
6
|
+
import { safeParseSchemaSync } from "../schema.js";
|
|
7
7
|
// Mirrors CONNECTOR_ID_REGEX in ../define.ts, which defineProvider() enforces.
|
|
8
8
|
// A single lowercase segment (no hyphen) is a valid id, so the trailing group
|
|
9
9
|
// is optional (`*`), matching providers like `kakaomap`, `kstartup`, `triple`.
|
|
10
10
|
const CONNECTOR_ID_REGEX = /^[a-z][a-z0-9]*(-[a-z][a-z0-9]*)*$/;
|
|
11
|
-
const VALID_AUTH_MODES = [
|
|
12
|
-
"none",
|
|
13
|
-
"platform-managed",
|
|
14
|
-
"credentials",
|
|
15
|
-
"oauth2",
|
|
16
|
-
];
|
|
11
|
+
const VALID_AUTH_MODES = ["none", "platform-managed", "credentials", "oauth2"];
|
|
17
12
|
const UPDATE_SNAPSHOT_ARGS = new Set(["-u", "--update-snapshots"]);
|
|
18
13
|
function isFixtureEnvelope(value) {
|
|
19
14
|
return (value !== null &&
|
|
@@ -60,9 +55,7 @@ function inferFixtureDir(providerId) {
|
|
|
60
55
|
.map((line) => line.match(/\(?((?:file:\/\/)?[^():]+\.test\.ts)/)?.[1])
|
|
61
56
|
.find((file) => file !== undefined);
|
|
62
57
|
if (testFile) {
|
|
63
|
-
const pathname = testFile.startsWith("file://")
|
|
64
|
-
? new URL(testFile).pathname
|
|
65
|
-
: testFile;
|
|
58
|
+
const pathname = testFile.startsWith("file://") ? new URL(testFile).pathname : testFile;
|
|
66
59
|
return `${pathname.replace(/\/[^/]+$/, "")}/../__fixtures__`;
|
|
67
60
|
}
|
|
68
61
|
return `providers/${providerId}/__fixtures__`;
|
package/dist/types.d.ts
CHANGED
|
@@ -1418,6 +1418,19 @@ export interface OperationContractMetadata {
|
|
|
1418
1418
|
deprecation?: OperationDeprecationMetadata;
|
|
1419
1419
|
}
|
|
1420
1420
|
export interface OperationDefinition<TInput extends SchemaLike = SchemaLike, TOutput extends SchemaLike = SchemaLike> {
|
|
1421
|
+
/**
|
|
1422
|
+
* Short English display title for the operation. The SDK passes it through
|
|
1423
|
+
* verbatim; the APIFuse registry derives the operation's en locale title
|
|
1424
|
+
* baseline from it (`docs.titleKey` remains available as an explicit key
|
|
1425
|
+
* override).
|
|
1426
|
+
*/
|
|
1427
|
+
title?: string;
|
|
1428
|
+
/**
|
|
1429
|
+
* Raw English operation description. The SDK passes it through verbatim;
|
|
1430
|
+
* keyed descriptions via `descriptionKey` remain the primary flow, and
|
|
1431
|
+
* provider lint rules for raw prose descriptions still apply.
|
|
1432
|
+
*/
|
|
1433
|
+
description?: string;
|
|
1421
1434
|
descriptionKey?: ProviderLocaleKeyInput;
|
|
1422
1435
|
docs?: OperationDocMeta;
|
|
1423
1436
|
whenToUseKeys?: readonly ProviderLocaleKeyInput[];
|
|
@@ -1447,10 +1460,54 @@ export interface OperationDefinition<TInput extends SchemaLike = SchemaLike, TOu
|
|
|
1447
1460
|
healthCheck?: HealthCheckSuite<InferSchemaOutput<TInput>, InferSchemaOutput<TOutput>>;
|
|
1448
1461
|
healthCheckUnsupported?: HealthCheckUnsupported;
|
|
1449
1462
|
}
|
|
1463
|
+
/**
|
|
1464
|
+
* Author-declared deployment overrides accepted as the optional top-level
|
|
1465
|
+
* `deployment` key on `defineProvider()`.
|
|
1466
|
+
*
|
|
1467
|
+
* The SDK passes this object through VERBATIM onto the returned provider
|
|
1468
|
+
* definition — it is typed here but deliberately not deep-validated: the
|
|
1469
|
+
* APIFuse registry builder owns deployment validation and resolves omitted
|
|
1470
|
+
* fields against the runtime deployment profiles. The shape mirrors the
|
|
1471
|
+
* registry's `ProviderDeploymentOverrides` contract; every field is
|
|
1472
|
+
* optional. Note that the deployment `runtime` axis
|
|
1473
|
+
* (`shared`/`dedicated`/`browser`) is distinct from the provider execution
|
|
1474
|
+
* `runtime` (`standard`/`shared`/`browser`).
|
|
1475
|
+
*/
|
|
1476
|
+
export interface ProviderDeploymentOverrides {
|
|
1477
|
+
runtime?: "shared" | "dedicated" | "browser";
|
|
1478
|
+
language?: "typescript" | "python";
|
|
1479
|
+
replicas?: number;
|
|
1480
|
+
hpa?: {
|
|
1481
|
+
enabled: boolean;
|
|
1482
|
+
minReplicas?: number;
|
|
1483
|
+
maxReplicas?: number;
|
|
1484
|
+
targetCPUUtilizationPercentage?: number;
|
|
1485
|
+
};
|
|
1486
|
+
resources?: {
|
|
1487
|
+
cpu: string;
|
|
1488
|
+
memory: string;
|
|
1489
|
+
};
|
|
1490
|
+
cache?: {
|
|
1491
|
+
redis?: {
|
|
1492
|
+
enabled: boolean;
|
|
1493
|
+
url?: string;
|
|
1494
|
+
};
|
|
1495
|
+
};
|
|
1496
|
+
network?: {
|
|
1497
|
+
additionalTcpPorts?: number[];
|
|
1498
|
+
};
|
|
1499
|
+
buildContext?: string;
|
|
1500
|
+
}
|
|
1450
1501
|
export interface ProviderDefinition {
|
|
1451
1502
|
id: string;
|
|
1452
1503
|
version: string;
|
|
1453
1504
|
runtime: "standard" | "shared" | "browser";
|
|
1505
|
+
/**
|
|
1506
|
+
* Optional deployment overrides, passed through verbatim from
|
|
1507
|
+
* `defineProvider({ deployment })`. Validation and profile resolution are
|
|
1508
|
+
* owned by the APIFuse registry builder, not the SDK.
|
|
1509
|
+
*/
|
|
1510
|
+
deployment?: ProviderDeploymentOverrides;
|
|
1454
1511
|
allowedHosts?: string[];
|
|
1455
1512
|
stealth?: {
|
|
1456
1513
|
profile: string;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export declare const NEEDS_INPUT_STATUS: "needs_input";
|
|
2
|
+
export interface ProviderSelectionOption {
|
|
3
|
+
readonly selection_value: string;
|
|
4
|
+
readonly label: string;
|
|
5
|
+
readonly [extra: string]: unknown;
|
|
6
|
+
}
|
|
7
|
+
export interface ProviderRequiredSelection {
|
|
8
|
+
readonly selection_key: string;
|
|
9
|
+
readonly label: string;
|
|
10
|
+
readonly required: boolean;
|
|
11
|
+
readonly selection_type?: string;
|
|
12
|
+
readonly valid_options: readonly ProviderSelectionOption[];
|
|
13
|
+
readonly [extra: string]: unknown;
|
|
14
|
+
}
|
|
15
|
+
export interface ProviderSelectedOption {
|
|
16
|
+
readonly selection_key: string;
|
|
17
|
+
readonly selection_value: string;
|
|
18
|
+
/** Free-text answer for text-kind selections. */
|
|
19
|
+
readonly text?: string;
|
|
20
|
+
/** Quantity for quantity-kind selections. */
|
|
21
|
+
readonly quantity?: number;
|
|
22
|
+
}
|
|
23
|
+
export interface ProviderNeedsInputPayload {
|
|
24
|
+
readonly status: typeof NEEDS_INPUT_STATUS;
|
|
25
|
+
readonly required_selections: readonly ProviderRequiredSelection[];
|
|
26
|
+
readonly selected_options?: readonly ProviderSelectedOption[];
|
|
27
|
+
/** Provider-specific fresh state token(s), e.g. `reservation_state`. */
|
|
28
|
+
readonly [extra: string]: unknown;
|
|
29
|
+
}
|
|
30
|
+
export declare function isProviderNeedsInputPayload(value: unknown): value is ProviderNeedsInputPayload;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// Official cross-provider contract for user-input round-trips.
|
|
2
|
+
//
|
|
3
|
+
// Doctrine (born from the 2026-07-20 CatchTable reserve incident): an
|
|
4
|
+
// operation MUST NOT dead-end on a problem the end user can resolve by
|
|
5
|
+
// choosing among live options. Instead of throwing, the provider returns a
|
|
6
|
+
// SUCCESSFUL payload with `status: "needs_input"` that carries everything a
|
|
7
|
+
// consumer-side agent needs to relay the choice verbatim and retry:
|
|
8
|
+
//
|
|
9
|
+
// - `required_selections`: only the still-pending questions, each with
|
|
10
|
+
// human-readable `label`s and `valid_options` the agent shows the user
|
|
11
|
+
// as-is. The agent never chooses on the user's behalf.
|
|
12
|
+
// - `selected_options`: selections already settled, echoed so the follow-up
|
|
13
|
+
// call keeps them without the agent reconstructing anything.
|
|
14
|
+
// - a fresh provider-specific state token (e.g. `reservation_state`) minted
|
|
15
|
+
// at response time, so the retry never races an expired token.
|
|
16
|
+
//
|
|
17
|
+
// Keeping this success-shaped (instead of error `details`) is deliberate:
|
|
18
|
+
// consumer error-shaping layers routinely strip error metadata, and a model
|
|
19
|
+
// that only sees "error" narrates failure to the user. Complex recovery
|
|
20
|
+
// logic belongs to the system, not the model.
|
|
21
|
+
//
|
|
22
|
+
// Deliberately ABSENT: retry templates, next-action routing, or any other
|
|
23
|
+
// agent choreography. Provider payloads carry upstream-backed data only; how
|
|
24
|
+
// to phrase the ask and shape the retry call is the consumer's contract
|
|
25
|
+
// (apifuse#1030). The retry is fully determined by data: copy the echoed
|
|
26
|
+
// selected_options, add the user's new answers, resend with the fresh state.
|
|
27
|
+
export const NEEDS_INPUT_STATUS = "needs_input";
|
|
28
|
+
function isRecord(value) {
|
|
29
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
30
|
+
}
|
|
31
|
+
function isSelectionOption(value) {
|
|
32
|
+
return (isRecord(value) &&
|
|
33
|
+
typeof value.selection_value === "string" &&
|
|
34
|
+
typeof value.label === "string");
|
|
35
|
+
}
|
|
36
|
+
function isRequiredSelection(value) {
|
|
37
|
+
return (isRecord(value) &&
|
|
38
|
+
typeof value.selection_key === "string" &&
|
|
39
|
+
typeof value.label === "string" &&
|
|
40
|
+
typeof value.required === "boolean" &&
|
|
41
|
+
Array.isArray(value.valid_options) &&
|
|
42
|
+
value.valid_options.every(isSelectionOption));
|
|
43
|
+
}
|
|
44
|
+
function isSelectedOption(value) {
|
|
45
|
+
return (isRecord(value) &&
|
|
46
|
+
typeof value.selection_key === "string" &&
|
|
47
|
+
typeof value.selection_value === "string");
|
|
48
|
+
}
|
|
49
|
+
export function isProviderNeedsInputPayload(value) {
|
|
50
|
+
if (!isRecord(value)) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
if (value.status !== NEEDS_INPUT_STATUS ||
|
|
54
|
+
!Array.isArray(value.required_selections) ||
|
|
55
|
+
!value.required_selections.every(isRequiredSelection)) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
// A needs_input with nothing to ask AND nothing settled to echo is a
|
|
59
|
+
// no-op dead end — reject it so providers cannot ship it accidentally.
|
|
60
|
+
if (value.required_selections.length > 0) {
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
return (Array.isArray(value.selected_options) &&
|
|
64
|
+
value.selected_options.length > 0 &&
|
|
65
|
+
value.selected_options.every(isSelectedOption));
|
|
66
|
+
}
|