@apifuse/provider-sdk 2.2.0-beta.3 → 2.2.0-beta.5
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 +53 -0
- package/CHANGELOG.md +8 -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 +266 -34
- 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 +104 -3
- package/dist/server/self-test.js +673 -115
- package/dist/server/serve.d.ts +3 -3
- package/dist/server/serve.js +37 -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 +12 -7
- package/src/server/self-test-redaction.ts +2 -2
- package/src/server/self-test.ts +857 -132
- package/src/server/serve.ts +89 -238
- 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/src/server/serve.ts
CHANGED
|
@@ -3,63 +3,60 @@ import { join } from "node:path";
|
|
|
3
3
|
|
|
4
4
|
import { Hono } from "hono";
|
|
5
5
|
import { z } from "zod";
|
|
6
|
-
import { AuthAbortError, createAuthFlowHelpers } from "../auth";
|
|
6
|
+
import { AuthAbortError, createAuthFlowHelpers } from "../auth.js";
|
|
7
7
|
import {
|
|
8
8
|
AuthError,
|
|
9
9
|
isProviderError,
|
|
10
10
|
isSessionExpiredError,
|
|
11
11
|
isTransportError,
|
|
12
12
|
ProviderError,
|
|
13
|
-
} from "../errors";
|
|
13
|
+
} from "../errors.js";
|
|
14
14
|
import {
|
|
15
15
|
loadProviderLocaleCatalogs,
|
|
16
16
|
localizeAuthTurn,
|
|
17
17
|
type ProviderLocaleCatalogMap,
|
|
18
|
-
} from "../i18n/catalog";
|
|
19
|
-
import type { ProviderLocale } from "../i18n/keys";
|
|
18
|
+
} from "../i18n/catalog.js";
|
|
19
|
+
import type { ProviderLocale } from "../i18n/keys.js";
|
|
20
20
|
import {
|
|
21
21
|
categoryForStatus,
|
|
22
22
|
isRetryableCategory,
|
|
23
23
|
PROVIDER_OBSERVABILITY_TAXONOMY_VERSION,
|
|
24
24
|
type ProviderErrorCategory,
|
|
25
|
-
} from "../observability";
|
|
26
|
-
import { createScratchpad } from "../runtime/auth-flow";
|
|
27
|
-
import { createBrowserClient } from "../runtime/browser";
|
|
28
|
-
import { createProviderCache } from "../runtime/cache";
|
|
25
|
+
} from "../observability.js";
|
|
26
|
+
import { createScratchpad } from "../runtime/auth-flow.js";
|
|
27
|
+
import { createBrowserClient } from "../runtime/browser.js";
|
|
28
|
+
import { createProviderCache } from "../runtime/cache.js";
|
|
29
29
|
import {
|
|
30
30
|
createProviderChoiceContext,
|
|
31
31
|
PROVIDER_RUNTIME_CHOICE_TOKEN_MASTER_SECRET_ENV,
|
|
32
|
-
} from "../runtime/choice";
|
|
33
|
-
import { createCredentialContext } from "../runtime/credential";
|
|
34
|
-
import { createEnvContext } from "../runtime/env";
|
|
35
|
-
import { executeOperation } from "../runtime/executor";
|
|
36
|
-
import { createHttpClient } from "../runtime/http";
|
|
37
|
-
import { wrapWithInstrumentation } from "../runtime/instrumentation";
|
|
38
|
-
import { getProviderBaseUrl } from "../runtime/provider";
|
|
32
|
+
} from "../runtime/choice.js";
|
|
33
|
+
import { createCredentialContext } from "../runtime/credential.js";
|
|
34
|
+
import { createEnvContext } from "../runtime/env.js";
|
|
35
|
+
import { executeOperation } from "../runtime/executor.js";
|
|
36
|
+
import { createHttpClient } from "../runtime/http.js";
|
|
37
|
+
import { wrapWithInstrumentation } from "../runtime/instrumentation.js";
|
|
38
|
+
import { getProviderBaseUrl } from "../runtime/provider.js";
|
|
39
39
|
import {
|
|
40
40
|
PROXY_AUTH_IP_DENIED_CODE,
|
|
41
41
|
PROXY_EDGE_AUTH_REJECTED_CODE,
|
|
42
42
|
PROXY_POOL_EXHAUSTED_CODE,
|
|
43
|
-
} from "../runtime/proxy-errors";
|
|
44
|
-
import {
|
|
45
|
-
PROVIDER_TELEMETRY_HEADER,
|
|
46
|
-
ProxyTelemetryCollector,
|
|
47
|
-
} from "../runtime/proxy-telemetry";
|
|
43
|
+
} from "../runtime/proxy-errors.js";
|
|
44
|
+
import { PROVIDER_TELEMETRY_HEADER, ProxyTelemetryCollector } from "../runtime/proxy-telemetry.js";
|
|
48
45
|
import {
|
|
49
46
|
createProviderRuntimeStateFromEnv,
|
|
50
47
|
createUnsupportedProviderRuntimeState,
|
|
51
|
-
} from "../runtime/state";
|
|
52
|
-
import { createStealthClient } from "../runtime/stealth";
|
|
53
|
-
import { createSttClientFromEnv } from "../runtime/stt";
|
|
54
|
-
import { createTraceContext } from "../runtime/trace";
|
|
55
|
-
import { parseSchema } from "../schema";
|
|
56
|
-
import { getStealthProfile } from "../stealth/profiles";
|
|
48
|
+
} from "../runtime/state.js";
|
|
49
|
+
import { createStealthClient } from "../runtime/stealth.js";
|
|
50
|
+
import { createSttClientFromEnv } from "../runtime/stt.js";
|
|
51
|
+
import { createTraceContext } from "../runtime/trace.js";
|
|
52
|
+
import { parseSchema } from "../schema.js";
|
|
53
|
+
import { getStealthProfile } from "../stealth/profiles.js";
|
|
57
54
|
import {
|
|
58
55
|
APIFUSE_STREAM_DONE_EVENT,
|
|
59
56
|
APIFUSE_STREAM_ERROR_EVENT,
|
|
60
57
|
encodeSseEvent,
|
|
61
58
|
error as streamError,
|
|
62
|
-
} from "../stream";
|
|
59
|
+
} from "../stream.js";
|
|
63
60
|
import type {
|
|
64
61
|
AuthContext,
|
|
65
62
|
AuthTurn,
|
|
@@ -76,13 +73,14 @@ import type {
|
|
|
76
73
|
ProviderStreamEvent,
|
|
77
74
|
StealthClient,
|
|
78
75
|
SttContext,
|
|
79
|
-
} from "../types";
|
|
76
|
+
} from "../types.js";
|
|
80
77
|
import {
|
|
81
78
|
createSelfTestApp,
|
|
79
|
+
createSelfTestAuthFlowInvoke,
|
|
82
80
|
createSelfTestInvoke,
|
|
83
81
|
resolveSelfTestPort,
|
|
84
|
-
} from "./self-test";
|
|
85
|
-
import { resolveSelfTestMasterSecrets } from "./self-test-token";
|
|
82
|
+
} from "./self-test.js";
|
|
83
|
+
import { resolveSelfTestMasterSecrets } from "./self-test-token.js";
|
|
86
84
|
import {
|
|
87
85
|
type AuthFlowRequest,
|
|
88
86
|
AuthFlowRequestSchema,
|
|
@@ -93,7 +91,7 @@ import {
|
|
|
93
91
|
OperationRequestSchema,
|
|
94
92
|
type OperationResponse,
|
|
95
93
|
type OperationSuccessResponse,
|
|
96
|
-
} from "./types";
|
|
94
|
+
} from "./types.js";
|
|
97
95
|
|
|
98
96
|
const DEFAULT_HOST = "0.0.0.0";
|
|
99
97
|
const DEFAULT_PORT = 3000;
|
|
@@ -157,9 +155,7 @@ function createStealthStub(): StealthClient {
|
|
|
157
155
|
};
|
|
158
156
|
}
|
|
159
157
|
|
|
160
|
-
function getProviderStealthBaseUrl(
|
|
161
|
-
provider: ProviderDefinition,
|
|
162
|
-
): string | undefined {
|
|
158
|
+
function getProviderStealthBaseUrl(provider: ProviderDefinition): string | undefined {
|
|
163
159
|
const baseUrl = getProviderBaseUrl(provider);
|
|
164
160
|
if (baseUrl) {
|
|
165
161
|
return baseUrl;
|
|
@@ -169,15 +165,10 @@ function getProviderStealthBaseUrl(
|
|
|
169
165
|
}
|
|
170
166
|
|
|
171
167
|
function getProviderStealthProfile(provider: ProviderDefinition) {
|
|
172
|
-
return provider.stealth?.profile
|
|
173
|
-
? getStealthProfile(provider.stealth.profile)
|
|
174
|
-
: undefined;
|
|
168
|
+
return provider.stealth?.profile ? getStealthProfile(provider.stealth.profile) : undefined;
|
|
175
169
|
}
|
|
176
170
|
|
|
177
|
-
function isProductionProviderBrowserMode(
|
|
178
|
-
provider: ProviderDefinition,
|
|
179
|
-
env = process.env,
|
|
180
|
-
): boolean {
|
|
171
|
+
function isProductionProviderBrowserMode(provider: ProviderDefinition, env = process.env): boolean {
|
|
181
172
|
if (provider.runtime !== "browser") {
|
|
182
173
|
return false;
|
|
183
174
|
}
|
|
@@ -186,9 +177,7 @@ function isProductionProviderBrowserMode(
|
|
|
186
177
|
return true;
|
|
187
178
|
}
|
|
188
179
|
|
|
189
|
-
return
|
|
190
|
-
env.NODE_ENV === "production" && env.APIFUSE__PROVIDER__ID === provider.id
|
|
191
|
-
);
|
|
180
|
+
return env.NODE_ENV === "production" && env.APIFUSE__PROVIDER__ID === provider.id;
|
|
192
181
|
}
|
|
193
182
|
|
|
194
183
|
export function resolveProviderProxyAffinityKey(
|
|
@@ -196,21 +185,16 @@ export function resolveProviderProxyAffinityKey(
|
|
|
196
185
|
request: OperationRequest,
|
|
197
186
|
operationId: string,
|
|
198
187
|
): string {
|
|
199
|
-
const connectionKey =
|
|
200
|
-
resolveOperationConnectionId(request) ?? request.connection?.externalRef;
|
|
188
|
+
const connectionKey = resolveOperationConnectionId(request) ?? request.connection?.externalRef;
|
|
201
189
|
const affinity =
|
|
202
|
-
typeof provider.proxy === "object"
|
|
203
|
-
? provider.proxy.session?.affinity
|
|
204
|
-
: undefined;
|
|
190
|
+
typeof provider.proxy === "object" ? provider.proxy.session?.affinity : undefined;
|
|
205
191
|
if (affinity === "operation") {
|
|
206
192
|
return `${provider.id}/${operationId}`;
|
|
207
193
|
}
|
|
208
194
|
return connectionKey ?? provider.id;
|
|
209
195
|
}
|
|
210
196
|
|
|
211
|
-
function resolveOperationConnectionId(
|
|
212
|
-
request: OperationRequest,
|
|
213
|
-
): string | undefined {
|
|
197
|
+
function resolveOperationConnectionId(request: OperationRequest): string | undefined {
|
|
214
198
|
return request.connection?.id ?? request.connectionId;
|
|
215
199
|
}
|
|
216
200
|
|
|
@@ -227,11 +211,7 @@ function createProviderContext(
|
|
|
227
211
|
const stealthProfile = getProviderStealthProfile(provider);
|
|
228
212
|
const proxyClientOptions = {
|
|
229
213
|
upstream: { proxy: provider.proxy },
|
|
230
|
-
affinityKey: resolveProviderProxyAffinityKey(
|
|
231
|
-
provider,
|
|
232
|
-
request,
|
|
233
|
-
operationId,
|
|
234
|
-
),
|
|
214
|
+
affinityKey: resolveProviderProxyAffinityKey(provider, request, operationId),
|
|
235
215
|
telemetry: proxyTelemetry,
|
|
236
216
|
};
|
|
237
217
|
let wrappedContext: ProviderContext | undefined;
|
|
@@ -270,11 +250,7 @@ function createProviderContext(
|
|
|
270
250
|
state,
|
|
271
251
|
stealth: stealthBaseUrl
|
|
272
252
|
? stealthProfile
|
|
273
|
-
? createStealthClient(
|
|
274
|
-
stealthBaseUrl,
|
|
275
|
-
stealthProfile.name,
|
|
276
|
-
stealthClientOptions,
|
|
277
|
-
)
|
|
253
|
+
? createStealthClient(stealthBaseUrl, stealthProfile.name, stealthClientOptions)
|
|
278
254
|
: createStealthClient(stealthBaseUrl, stealthClientOptions)
|
|
279
255
|
: createStealthStub(),
|
|
280
256
|
browser:
|
|
@@ -387,11 +363,7 @@ function createAuthFlowContext(
|
|
|
387
363
|
http: createHttpClient(baseUrl, proxyClientOptions),
|
|
388
364
|
stealth: stealthBaseUrl
|
|
389
365
|
? stealthProfile
|
|
390
|
-
? createStealthClient(
|
|
391
|
-
stealthBaseUrl,
|
|
392
|
-
stealthProfile.name,
|
|
393
|
-
stealthClientOptions,
|
|
394
|
-
)
|
|
366
|
+
? createStealthClient(stealthBaseUrl, stealthProfile.name, stealthClientOptions)
|
|
395
367
|
: createStealthClient(stealthBaseUrl, stealthClientOptions)
|
|
396
368
|
: createStealthStub(),
|
|
397
369
|
env: createEnvContext(provider.secrets?.map((secret) => secret.name)),
|
|
@@ -504,10 +476,7 @@ function zodDetails(error: z.ZodError): Array<{
|
|
|
504
476
|
}));
|
|
505
477
|
}
|
|
506
478
|
|
|
507
|
-
function toErrorResponse(
|
|
508
|
-
error: unknown,
|
|
509
|
-
requestId?: string,
|
|
510
|
-
): OperationErrorResponse {
|
|
479
|
+
function toErrorResponse(error: unknown, requestId?: string): OperationErrorResponse {
|
|
511
480
|
if (isProviderError(error)) {
|
|
512
481
|
const details = publicProviderErrorDetails(error);
|
|
513
482
|
return {
|
|
@@ -645,9 +614,7 @@ function publicProviderErrorMessage(error: ProviderError): string {
|
|
|
645
614
|
return error.message;
|
|
646
615
|
}
|
|
647
616
|
|
|
648
|
-
function toStatusCode(
|
|
649
|
-
error: unknown,
|
|
650
|
-
): 400 | 401 | 404 | 429 | 500 | 502 | 503 | 504 {
|
|
617
|
+
function toStatusCode(error: unknown): 400 | 401 | 404 | 429 | 500 | 502 | 503 | 504 {
|
|
651
618
|
if (error instanceof z.ZodError) {
|
|
652
619
|
return 400;
|
|
653
620
|
}
|
|
@@ -702,20 +669,15 @@ function logProviderError(
|
|
|
702
669
|
status: number,
|
|
703
670
|
cost: ProviderRequestCost,
|
|
704
671
|
): void {
|
|
705
|
-
const code =
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
: "internal_error";
|
|
672
|
+
const code = isProviderError(error)
|
|
673
|
+
? (error.code ?? "provider_error")
|
|
674
|
+
: error instanceof z.ZodError
|
|
675
|
+
? "invalid_request"
|
|
676
|
+
: "internal_error";
|
|
711
677
|
const errorClass = error instanceof Error ? error.name : typeof error;
|
|
712
678
|
const message = error instanceof Error ? error.message : String(error);
|
|
713
|
-
const details =
|
|
714
|
-
|
|
715
|
-
? providerObservabilityDetails(error)
|
|
716
|
-
: undefined;
|
|
717
|
-
const emit =
|
|
718
|
-
typeof logger === "function" ? logger : defaultProviderServerLogger;
|
|
679
|
+
const details = isProviderError(error) ? providerObservabilityDetails(error) : undefined;
|
|
680
|
+
const emit = typeof logger === "function" ? logger : defaultProviderServerLogger;
|
|
719
681
|
emit({
|
|
720
682
|
level: status >= 500 ? "error" : "warn",
|
|
721
683
|
event: "provider_request_failed",
|
|
@@ -750,8 +712,7 @@ function logProviderCleanupError(
|
|
|
750
712
|
resource: "browser" | "stealth",
|
|
751
713
|
error: unknown,
|
|
752
714
|
): void {
|
|
753
|
-
const emit =
|
|
754
|
-
typeof logger === "function" ? logger : defaultProviderServerLogger;
|
|
715
|
+
const emit = typeof logger === "function" ? logger : defaultProviderServerLogger;
|
|
755
716
|
const errorClass = error instanceof Error ? error.name : typeof error;
|
|
756
717
|
const message = error instanceof Error ? error.message : String(error);
|
|
757
718
|
emit({
|
|
@@ -776,8 +737,7 @@ function logProviderSuccess(
|
|
|
776
737
|
status: number,
|
|
777
738
|
cost: ProviderRequestCost,
|
|
778
739
|
): void {
|
|
779
|
-
const emit =
|
|
780
|
-
typeof logger === "function" ? logger : defaultProviderServerLogger;
|
|
740
|
+
const emit = typeof logger === "function" ? logger : defaultProviderServerLogger;
|
|
781
741
|
emit({
|
|
782
742
|
level: "info",
|
|
783
743
|
event: "provider_request_completed",
|
|
@@ -823,18 +783,13 @@ function toJsonSuccessResponse(
|
|
|
823
783
|
};
|
|
824
784
|
}
|
|
825
785
|
|
|
826
|
-
function isAsyncIterable<T = unknown>(
|
|
827
|
-
value: unknown,
|
|
828
|
-
): value is AsyncIterable<T> {
|
|
786
|
+
function isAsyncIterable<T = unknown>(value: unknown): value is AsyncIterable<T> {
|
|
829
787
|
if (!value || typeof value !== "object") return false;
|
|
830
788
|
const iterator = Reflect.get(value, Symbol.asyncIterator);
|
|
831
789
|
return typeof iterator === "function";
|
|
832
790
|
}
|
|
833
791
|
|
|
834
|
-
function responseWithCleanup(
|
|
835
|
-
response: Response,
|
|
836
|
-
cleanup: RequestCleanup,
|
|
837
|
-
): Response {
|
|
792
|
+
function responseWithCleanup(response: Response, cleanup: RequestCleanup): Response {
|
|
838
793
|
if (!response.body) {
|
|
839
794
|
void cleanup();
|
|
840
795
|
return response;
|
|
@@ -883,10 +838,7 @@ async function validateSseEvent(
|
|
|
883
838
|
const transport = getSseTransport(operation);
|
|
884
839
|
const schema = transport?.events?.[event.event];
|
|
885
840
|
if (!schema) {
|
|
886
|
-
if (
|
|
887
|
-
event.event === APIFUSE_STREAM_ERROR_EVENT ||
|
|
888
|
-
event.event === APIFUSE_STREAM_DONE_EVENT
|
|
889
|
-
) {
|
|
841
|
+
if (event.event === APIFUSE_STREAM_ERROR_EVENT || event.event === APIFUSE_STREAM_DONE_EVENT) {
|
|
890
842
|
return event;
|
|
891
843
|
}
|
|
892
844
|
throw new ProviderError(
|
|
@@ -899,11 +851,7 @@ async function validateSseEvent(
|
|
|
899
851
|
},
|
|
900
852
|
);
|
|
901
853
|
}
|
|
902
|
-
const data = await parseSchema(
|
|
903
|
-
schema,
|
|
904
|
-
event.data,
|
|
905
|
-
`transport.events.${event.event}`,
|
|
906
|
-
);
|
|
854
|
+
const data = await parseSchema(schema, event.data, `transport.events.${event.event}`);
|
|
907
855
|
return { ...event, data };
|
|
908
856
|
}
|
|
909
857
|
|
|
@@ -923,8 +871,7 @@ function assertStreamPayloadWithinLimit(
|
|
|
923
871
|
throw new ProviderError(
|
|
924
872
|
`Stream ${kind} exceeded declared byte limit (${actualBytes} > ${maxBytes}).`,
|
|
925
873
|
{
|
|
926
|
-
code:
|
|
927
|
-
kind === "event" ? "STREAM_EVENT_TOO_LARGE" : "STREAM_CHUNK_TOO_LARGE",
|
|
874
|
+
code: kind === "event" ? "STREAM_EVENT_TOO_LARGE" : "STREAM_CHUNK_TOO_LARGE",
|
|
928
875
|
retryable: false,
|
|
929
876
|
category: "input_validation",
|
|
930
877
|
fix:
|
|
@@ -969,15 +916,10 @@ function toSseResponse(
|
|
|
969
916
|
const validated = await validateSseEvent(operation, next.value);
|
|
970
917
|
const encodedEvent = encodeSseEvent(validated);
|
|
971
918
|
const encodedBytes = encoder.encode(encodedEvent);
|
|
972
|
-
assertStreamPayloadWithinLimit(
|
|
973
|
-
encodedBytes.byteLength,
|
|
974
|
-
transport?.maxEventBytes,
|
|
975
|
-
"event",
|
|
976
|
-
);
|
|
919
|
+
assertStreamPayloadWithinLimit(encodedBytes.byteLength, transport?.maxEventBytes, "event");
|
|
977
920
|
controller.enqueue(encodedBytes);
|
|
978
921
|
} catch (error) {
|
|
979
|
-
const message =
|
|
980
|
-
error instanceof Error ? error.message : "Stream failed";
|
|
922
|
+
const message = error instanceof Error ? error.message : "Stream failed";
|
|
981
923
|
controller.enqueue(
|
|
982
924
|
encoder.encode(
|
|
983
925
|
encodeSseEvent(
|
|
@@ -1024,11 +966,7 @@ function enforceStreamChunkLimit(
|
|
|
1024
966
|
return;
|
|
1025
967
|
}
|
|
1026
968
|
if (value) {
|
|
1027
|
-
assertStreamPayloadWithinLimit(
|
|
1028
|
-
byteLength(value),
|
|
1029
|
-
maxChunkBytes,
|
|
1030
|
-
"chunk",
|
|
1031
|
-
);
|
|
969
|
+
assertStreamPayloadWithinLimit(byteLength(value), maxChunkBytes, "chunk");
|
|
1032
970
|
controller.enqueue(value);
|
|
1033
971
|
}
|
|
1034
972
|
} catch (error) {
|
|
@@ -1048,10 +986,7 @@ function toStreamingResponse(
|
|
|
1048
986
|
requestId?: string,
|
|
1049
987
|
): Response {
|
|
1050
988
|
const transport = operation.transport?.kind ?? "json";
|
|
1051
|
-
if (
|
|
1052
|
-
transport === "sse" &&
|
|
1053
|
-
(result instanceof Response || result instanceof ReadableStream)
|
|
1054
|
-
) {
|
|
989
|
+
if (transport === "sse" && (result instanceof Response || result instanceof ReadableStream)) {
|
|
1055
990
|
void cleanup();
|
|
1056
991
|
throw new ProviderError(
|
|
1057
992
|
"SSE operations must return an AsyncIterable of typed stream.event(...) values.",
|
|
@@ -1065,20 +1000,13 @@ function toStreamingResponse(
|
|
|
1065
1000
|
}
|
|
1066
1001
|
if (result instanceof Response) {
|
|
1067
1002
|
const httpTransport = getHttpStreamTransport(operation);
|
|
1068
|
-
if (
|
|
1069
|
-
httpTransport &&
|
|
1070
|
-
result.body &&
|
|
1071
|
-
httpTransport?.maxChunkBytes !== undefined
|
|
1072
|
-
) {
|
|
1003
|
+
if (httpTransport && result.body && httpTransport?.maxChunkBytes !== undefined) {
|
|
1073
1004
|
return responseWithCleanup(
|
|
1074
|
-
new Response(
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
statusText: result.statusText,
|
|
1080
|
-
},
|
|
1081
|
-
),
|
|
1005
|
+
new Response(enforceStreamChunkLimit(result.body, httpTransport.maxChunkBytes), {
|
|
1006
|
+
headers: result.headers,
|
|
1007
|
+
status: result.status,
|
|
1008
|
+
statusText: result.statusText,
|
|
1009
|
+
}),
|
|
1082
1010
|
cleanup,
|
|
1083
1011
|
);
|
|
1084
1012
|
}
|
|
@@ -1098,8 +1026,7 @@ function toStreamingResponse(
|
|
|
1098
1026
|
: {
|
|
1099
1027
|
"Content-Type":
|
|
1100
1028
|
operation.transport?.kind === "http-stream"
|
|
1101
|
-
? (operation.transport.contentType ??
|
|
1102
|
-
"application/octet-stream")
|
|
1029
|
+
? (operation.transport.contentType ?? "application/octet-stream")
|
|
1103
1030
|
: "application/octet-stream",
|
|
1104
1031
|
},
|
|
1105
1032
|
}),
|
|
@@ -1119,18 +1046,14 @@ function toStreamingResponse(
|
|
|
1119
1046
|
);
|
|
1120
1047
|
}
|
|
1121
1048
|
|
|
1122
|
-
function getSseTransport(
|
|
1123
|
-
operation: OperationDefinition,
|
|
1124
|
-
): OperationSseTransport | undefined {
|
|
1049
|
+
function getSseTransport(operation: OperationDefinition): OperationSseTransport | undefined {
|
|
1125
1050
|
return operation.transport?.kind === "sse" ? operation.transport : undefined;
|
|
1126
1051
|
}
|
|
1127
1052
|
|
|
1128
1053
|
function getHttpStreamTransport(
|
|
1129
1054
|
operation: OperationDefinition,
|
|
1130
1055
|
): OperationHttpStreamTransport | undefined {
|
|
1131
|
-
return operation.transport?.kind === "http-stream"
|
|
1132
|
-
? operation.transport
|
|
1133
|
-
: undefined;
|
|
1056
|
+
return operation.transport?.kind === "http-stream" ? operation.transport : undefined;
|
|
1134
1057
|
}
|
|
1135
1058
|
|
|
1136
1059
|
function toAuthFlowResponse(
|
|
@@ -1151,9 +1074,7 @@ function toAuthFlowResponse(
|
|
|
1151
1074
|
};
|
|
1152
1075
|
}
|
|
1153
1076
|
|
|
1154
|
-
function authFlowLocaleFromHeaders(
|
|
1155
|
-
headers?: Record<string, string>,
|
|
1156
|
-
): ProviderLocale {
|
|
1077
|
+
function authFlowLocaleFromHeaders(headers?: Record<string, string>): ProviderLocale {
|
|
1157
1078
|
const header = Object.entries(headers ?? {}).find(
|
|
1158
1079
|
([key]) => key.toLowerCase() === "accept-language",
|
|
1159
1080
|
)?.[1];
|
|
@@ -1171,9 +1092,7 @@ function isAuthFlowLocale(value: string | undefined): value is ProviderLocale {
|
|
|
1171
1092
|
}
|
|
1172
1093
|
|
|
1173
1094
|
function isAuthTurn(value: unknown): value is AuthTurn {
|
|
1174
|
-
return
|
|
1175
|
-
!!value && typeof value === "object" && "kind" in value && "turnId" in value
|
|
1176
|
-
);
|
|
1095
|
+
return !!value && typeof value === "object" && "kind" in value && "turnId" in value;
|
|
1177
1096
|
}
|
|
1178
1097
|
|
|
1179
1098
|
function loadAuthFlowLocaleCatalogs(
|
|
@@ -1210,10 +1129,7 @@ function materializeAuthFlowTurn(
|
|
|
1210
1129
|
});
|
|
1211
1130
|
}
|
|
1212
1131
|
|
|
1213
|
-
function withAuthRequestHeaders(
|
|
1214
|
-
request: AuthFlowRequest,
|
|
1215
|
-
headers: Headers,
|
|
1216
|
-
): AuthFlowRequest {
|
|
1132
|
+
function withAuthRequestHeaders(request: AuthFlowRequest, headers: Headers): AuthFlowRequest {
|
|
1217
1133
|
return {
|
|
1218
1134
|
...request,
|
|
1219
1135
|
headers: {
|
|
@@ -1231,17 +1147,9 @@ async function handleOperation(
|
|
|
1231
1147
|
state: ProviderRuntimeState = createUnsupportedProviderRuntimeState(),
|
|
1232
1148
|
proxyTelemetry?: ProxyTelemetryCollector,
|
|
1233
1149
|
): Promise<Response | OperationResponse> {
|
|
1234
|
-
const ctx = createProviderContext(
|
|
1235
|
-
provider,
|
|
1236
|
-
request,
|
|
1237
|
-
operationId,
|
|
1238
|
-
options,
|
|
1239
|
-
state,
|
|
1240
|
-
proxyTelemetry,
|
|
1241
|
-
);
|
|
1150
|
+
const ctx = createProviderContext(provider, request, operationId, options, state, proxyTelemetry);
|
|
1242
1151
|
const operation = provider.operations[operationId];
|
|
1243
|
-
const streaming =
|
|
1244
|
-
operation?.transport?.kind && operation.transport.kind !== "json";
|
|
1152
|
+
const streaming = operation?.transport?.kind && operation.transport.kind !== "json";
|
|
1245
1153
|
let cleanupCalled = false;
|
|
1246
1154
|
const cleanup = async () => {
|
|
1247
1155
|
if (cleanupCalled) return;
|
|
@@ -1272,12 +1180,7 @@ async function handleOperation(
|
|
|
1272
1180
|
}
|
|
1273
1181
|
};
|
|
1274
1182
|
try {
|
|
1275
|
-
const result = await executeOperation(
|
|
1276
|
-
provider,
|
|
1277
|
-
operationId,
|
|
1278
|
-
ctx,
|
|
1279
|
-
request.input,
|
|
1280
|
-
);
|
|
1183
|
+
const result = await executeOperation(provider, operationId, ctx, request.input);
|
|
1281
1184
|
if (streaming && operation) {
|
|
1282
1185
|
return toStreamingResponse(operation, result, cleanup, request.requestId);
|
|
1283
1186
|
}
|
|
@@ -1321,12 +1224,7 @@ async function handleAuthFlow(
|
|
|
1321
1224
|
});
|
|
1322
1225
|
}
|
|
1323
1226
|
|
|
1324
|
-
const { context, getPatch } = createAuthFlowContext(
|
|
1325
|
-
provider,
|
|
1326
|
-
request,
|
|
1327
|
-
options,
|
|
1328
|
-
signal,
|
|
1329
|
-
);
|
|
1227
|
+
const { context, getPatch } = createAuthFlowContext(provider, request, options, signal);
|
|
1330
1228
|
try {
|
|
1331
1229
|
const result =
|
|
1332
1230
|
route === "start"
|
|
@@ -1474,17 +1372,8 @@ export function createServerApp(
|
|
|
1474
1372
|
.clone()
|
|
1475
1373
|
.json()
|
|
1476
1374
|
.catch(() => undefined);
|
|
1477
|
-
const body = withAuthRequestHeaders(
|
|
1478
|
-
|
|
1479
|
-
c.req.raw.headers,
|
|
1480
|
-
);
|
|
1481
|
-
const response = await handleAuthFlow(
|
|
1482
|
-
provider,
|
|
1483
|
-
body,
|
|
1484
|
-
"start",
|
|
1485
|
-
options,
|
|
1486
|
-
c.req.raw.signal,
|
|
1487
|
-
);
|
|
1375
|
+
const body = withAuthRequestHeaders(AuthFlowRequestSchema.parse(rawBody), c.req.raw.headers);
|
|
1376
|
+
const response = await handleAuthFlow(provider, body, "start", options, c.req.raw.signal);
|
|
1488
1377
|
logProviderSuccess(
|
|
1489
1378
|
logger,
|
|
1490
1379
|
provider,
|
|
@@ -1520,17 +1409,8 @@ export function createServerApp(
|
|
|
1520
1409
|
.clone()
|
|
1521
1410
|
.json()
|
|
1522
1411
|
.catch(() => undefined);
|
|
1523
|
-
const body = withAuthRequestHeaders(
|
|
1524
|
-
|
|
1525
|
-
c.req.raw.headers,
|
|
1526
|
-
);
|
|
1527
|
-
const response = await handleAuthFlow(
|
|
1528
|
-
provider,
|
|
1529
|
-
body,
|
|
1530
|
-
"continue",
|
|
1531
|
-
options,
|
|
1532
|
-
c.req.raw.signal,
|
|
1533
|
-
);
|
|
1412
|
+
const body = withAuthRequestHeaders(AuthFlowRequestSchema.parse(rawBody), c.req.raw.headers);
|
|
1413
|
+
const response = await handleAuthFlow(provider, body, "continue", options, c.req.raw.signal);
|
|
1534
1414
|
logProviderSuccess(
|
|
1535
1415
|
logger,
|
|
1536
1416
|
provider,
|
|
@@ -1566,17 +1446,8 @@ export function createServerApp(
|
|
|
1566
1446
|
.clone()
|
|
1567
1447
|
.json()
|
|
1568
1448
|
.catch(() => undefined);
|
|
1569
|
-
const body = withAuthRequestHeaders(
|
|
1570
|
-
|
|
1571
|
-
c.req.raw.headers,
|
|
1572
|
-
);
|
|
1573
|
-
const response = await handleAuthFlow(
|
|
1574
|
-
provider,
|
|
1575
|
-
body,
|
|
1576
|
-
"poll",
|
|
1577
|
-
options,
|
|
1578
|
-
c.req.raw.signal,
|
|
1579
|
-
);
|
|
1449
|
+
const body = withAuthRequestHeaders(AuthFlowRequestSchema.parse(rawBody), c.req.raw.headers);
|
|
1450
|
+
const response = await handleAuthFlow(provider, body, "poll", options, c.req.raw.signal);
|
|
1580
1451
|
logProviderSuccess(
|
|
1581
1452
|
logger,
|
|
1582
1453
|
provider,
|
|
@@ -1612,17 +1483,8 @@ export function createServerApp(
|
|
|
1612
1483
|
.clone()
|
|
1613
1484
|
.json()
|
|
1614
1485
|
.catch(() => undefined);
|
|
1615
|
-
const body = withAuthRequestHeaders(
|
|
1616
|
-
|
|
1617
|
-
c.req.raw.headers,
|
|
1618
|
-
);
|
|
1619
|
-
const response = await handleAuthFlow(
|
|
1620
|
-
provider,
|
|
1621
|
-
body,
|
|
1622
|
-
"refresh",
|
|
1623
|
-
options,
|
|
1624
|
-
c.req.raw.signal,
|
|
1625
|
-
);
|
|
1486
|
+
const body = withAuthRequestHeaders(AuthFlowRequestSchema.parse(rawBody), c.req.raw.headers);
|
|
1487
|
+
const response = await handleAuthFlow(provider, body, "refresh", options, c.req.raw.signal);
|
|
1626
1488
|
logProviderSuccess(
|
|
1627
1489
|
logger,
|
|
1628
1490
|
provider,
|
|
@@ -1658,17 +1520,8 @@ export function createServerApp(
|
|
|
1658
1520
|
.clone()
|
|
1659
1521
|
.json()
|
|
1660
1522
|
.catch(() => undefined);
|
|
1661
|
-
const body = withAuthRequestHeaders(
|
|
1662
|
-
|
|
1663
|
-
c.req.raw.headers,
|
|
1664
|
-
);
|
|
1665
|
-
const response = await handleAuthFlow(
|
|
1666
|
-
provider,
|
|
1667
|
-
body,
|
|
1668
|
-
"abort",
|
|
1669
|
-
options,
|
|
1670
|
-
c.req.raw.signal,
|
|
1671
|
-
);
|
|
1523
|
+
const body = withAuthRequestHeaders(AuthFlowRequestSchema.parse(rawBody), c.req.raw.headers);
|
|
1524
|
+
const response = await handleAuthFlow(provider, body, "abort", options, c.req.raw.signal);
|
|
1672
1525
|
logProviderSuccess(
|
|
1673
1526
|
logger,
|
|
1674
1527
|
provider,
|
|
@@ -1743,12 +1596,9 @@ export async function serve(
|
|
|
1743
1596
|
const bunRuntime = getBunServeRuntime();
|
|
1744
1597
|
|
|
1745
1598
|
if (bunRuntime === undefined) {
|
|
1746
|
-
throw new ProviderError(
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
code: "RUNTIME_UNSUPPORTED",
|
|
1750
|
-
},
|
|
1751
|
-
);
|
|
1599
|
+
throw new ProviderError("Bun runtime is required to start the provider server", {
|
|
1600
|
+
code: "RUNTIME_UNSUPPORTED",
|
|
1601
|
+
});
|
|
1752
1602
|
}
|
|
1753
1603
|
|
|
1754
1604
|
const app = createServerApp(provider, {
|
|
@@ -1770,6 +1620,7 @@ export async function serve(
|
|
|
1770
1620
|
const selfTestApp = createSelfTestApp(provider, {
|
|
1771
1621
|
secrets: selfTestSecrets,
|
|
1772
1622
|
invoke: createSelfTestInvoke(app),
|
|
1623
|
+
authFlow: createSelfTestAuthFlowInvoke(app),
|
|
1773
1624
|
});
|
|
1774
1625
|
bunRuntime.serve({
|
|
1775
1626
|
port: options.selfTestPort ?? resolveSelfTestPort(),
|
package/src/server/types.ts
CHANGED
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
|
-
import { HttpRetryPreset } from "../types";
|
|
3
|
+
import { HttpRetryPreset } from "../types.js";
|
|
4
4
|
|
|
5
|
-
export const ConnectionModeSchema = z.enum([
|
|
6
|
-
"oauth2",
|
|
7
|
-
"credentials",
|
|
8
|
-
"platform-managed",
|
|
9
|
-
"none",
|
|
10
|
-
]);
|
|
5
|
+
export const ConnectionModeSchema = z.enum(["oauth2", "credentials", "platform-managed", "none"]);
|
|
11
6
|
|
|
12
7
|
export const OperationConnectionSchema = z.object({
|
|
13
8
|
id: z.string(),
|
|
@@ -99,18 +94,10 @@ export const AuthFlowErrorResponseSchema = OperationErrorResponseSchema;
|
|
|
99
94
|
export type ConnectionMode = z.infer<typeof ConnectionModeSchema>;
|
|
100
95
|
export type OperationConnection = z.infer<typeof OperationConnectionSchema>;
|
|
101
96
|
export type OperationRequest = z.infer<typeof OperationRequestSchema>;
|
|
102
|
-
export type OperationSuccessResponse = z.infer<
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
export type OperationErrorResponse = z.infer<
|
|
106
|
-
typeof OperationErrorResponseSchema
|
|
107
|
-
>;
|
|
108
|
-
export type OperationResponse =
|
|
109
|
-
| OperationSuccessResponse
|
|
110
|
-
| OperationErrorResponse;
|
|
97
|
+
export type OperationSuccessResponse = z.infer<typeof OperationSuccessResponseSchema>;
|
|
98
|
+
export type OperationErrorResponse = z.infer<typeof OperationErrorResponseSchema>;
|
|
99
|
+
export type OperationResponse = OperationSuccessResponse | OperationErrorResponse;
|
|
111
100
|
export type AuthFlowRequest = z.infer<typeof AuthFlowRequestSchema>;
|
|
112
|
-
export type AuthFlowSuccessResponse = z.infer<
|
|
113
|
-
typeof AuthFlowSuccessResponseSchema
|
|
114
|
-
>;
|
|
101
|
+
export type AuthFlowSuccessResponse = z.infer<typeof AuthFlowSuccessResponseSchema>;
|
|
115
102
|
export type AuthFlowErrorResponse = z.infer<typeof AuthFlowErrorResponseSchema>;
|
|
116
103
|
export type AuthFlowResponse = AuthFlowSuccessResponse | AuthFlowErrorResponse;
|