@apifuse/provider-sdk 2.2.0-beta.12 → 2.2.0-beta.13
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 +201 -0
- package/CHANGELOG.md +10 -0
- package/README.md +26 -2
- package/bin/apifuse-pack-types.ts +30 -1
- package/bin/apifuse-record.ts +622 -57
- package/bin/apifuse-submit-check.ts +43 -10
- package/dist/define.d.ts +2 -1
- package/dist/define.js +61 -3
- package/dist/fixture-sanitization.d.ts +26 -0
- package/dist/fixture-sanitization.js +216 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -0
- package/dist/provider.d.ts +2 -1
- package/dist/provider.js +1 -0
- package/dist/runtime/http.js +86 -32
- package/dist/runtime/instrumentation.js +295 -9
- package/dist/runtime/native-network.d.ts +53 -0
- package/dist/runtime/native-network.js +477 -0
- package/dist/runtime/proxy-nodemaven.d.ts +14 -0
- package/dist/runtime/proxy-nodemaven.js +20 -2
- package/dist/runtime/request-options.d.ts +68 -1
- package/dist/runtime/request-options.js +548 -0
- package/dist/runtime/stealth.d.ts +3 -1
- package/dist/runtime/stealth.js +239 -39
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/self-test-input-tokens.d.ts +2 -1
- package/dist/server/self-test-input-tokens.js +18 -14
- package/dist/stream-evidence.d.ts +74 -0
- package/dist/stream-evidence.js +785 -0
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/index.js +1 -1
- package/dist/testing/run.d.ts +32 -2
- package/dist/testing/run.js +451 -19
- package/dist/types.d.ts +162 -0
- package/package.json +2 -1
- package/src/define.ts +81 -3
- package/src/fixture-sanitization.ts +247 -0
- package/src/index.ts +37 -0
- package/src/provider.ts +37 -0
- package/src/runtime/http.ts +144 -38
- package/src/runtime/instrumentation.ts +424 -8
- package/src/runtime/native-network.ts +600 -0
- package/src/runtime/proxy-nodemaven.ts +37 -2
- package/src/runtime/request-options.ts +680 -1
- package/src/runtime/stealth.ts +293 -40
- package/src/server/index.ts +4 -1
- package/src/server/self-test-input-tokens.ts +29 -14
- package/src/stream-evidence.ts +988 -0
- package/src/testing/index.ts +9 -1
- package/src/testing/run.ts +608 -12
- package/src/types.ts +194 -0
package/src/provider.ts
CHANGED
|
@@ -94,6 +94,26 @@ export type {
|
|
|
94
94
|
HttpRetryOptions,
|
|
95
95
|
HttpRetrySummary,
|
|
96
96
|
InferSchemaOutput,
|
|
97
|
+
NativeContext,
|
|
98
|
+
NativeNetworkClient,
|
|
99
|
+
NativeNetworkCloseReason,
|
|
100
|
+
NativeNetworkConnection,
|
|
101
|
+
NativeNetworkConnectInput,
|
|
102
|
+
NativeNetworkConnectOptions,
|
|
103
|
+
NativeNetworkDynamicGrantOptions,
|
|
104
|
+
NativeNetworkEgressGrant,
|
|
105
|
+
NativeProviderConfig,
|
|
106
|
+
NativeProviderContext,
|
|
107
|
+
NativeProxyDrainHandler,
|
|
108
|
+
NativeProxyEgressInfo,
|
|
109
|
+
NativeProxyExpiringEvent,
|
|
110
|
+
NativeProxyExpiringReason,
|
|
111
|
+
NativeTcpDynamicEgressRule,
|
|
112
|
+
NativeTcpEgressGrant,
|
|
113
|
+
NativeTcpEgressRule,
|
|
114
|
+
NativeTcpPortRange,
|
|
115
|
+
NativeTcpTlsMode,
|
|
116
|
+
NativeTlsConnectOptions,
|
|
97
117
|
OperationApprovalPolicy,
|
|
98
118
|
OperationContractMetadata,
|
|
99
119
|
OperationDefinition,
|
|
@@ -116,6 +136,8 @@ export type {
|
|
|
116
136
|
ProviderContext,
|
|
117
137
|
ProviderDefinition,
|
|
118
138
|
ProviderDeploymentOverrides,
|
|
139
|
+
ProviderFileRef,
|
|
140
|
+
ProviderFilesContext,
|
|
119
141
|
ProviderLocale,
|
|
120
142
|
ProviderLocaleKey,
|
|
121
143
|
ProviderLocaleKeyInput,
|
|
@@ -123,6 +145,7 @@ export type {
|
|
|
123
145
|
ProviderProxyPolicy,
|
|
124
146
|
ProviderPublicConnectionMode,
|
|
125
147
|
ProviderPublicProfile,
|
|
148
|
+
ProviderResolvedFile,
|
|
126
149
|
ProviderRuntimeState,
|
|
127
150
|
ProviderStateDurationString,
|
|
128
151
|
ProviderStateNamespace,
|
|
@@ -135,6 +158,20 @@ export type {
|
|
|
135
158
|
StateValue,
|
|
136
159
|
StateWriteOptions,
|
|
137
160
|
} from "./types.js";
|
|
161
|
+
export {
|
|
162
|
+
createNativeNetworkClient,
|
|
163
|
+
deriveNativeCredentialAffinityKey,
|
|
164
|
+
NativeIdleTimeoutError,
|
|
165
|
+
NativeNetworkError,
|
|
166
|
+
NativeProxyExpiredError,
|
|
167
|
+
resolveNativeGatewayProxy,
|
|
168
|
+
type NativeGatewayProxy,
|
|
169
|
+
type NativeGatewayProxyResolutionInput,
|
|
170
|
+
type NativeGatewayProxySynthesizer,
|
|
171
|
+
type NativeGatewayProxySynthesisInput,
|
|
172
|
+
type NativeNetworkClientOptions,
|
|
173
|
+
type NativeNetworkErrorCode,
|
|
174
|
+
} from "./runtime/native-network.js";
|
|
138
175
|
export {
|
|
139
176
|
HttpRetryAfterPolicy,
|
|
140
177
|
HttpRetryDelayStrategy,
|
package/src/runtime/http.ts
CHANGED
|
@@ -28,7 +28,13 @@ import {
|
|
|
28
28
|
shouldRetryProxyTransportAttempt,
|
|
29
29
|
validateUnsafeProxyTransportRetryMethods,
|
|
30
30
|
} from "./proxy-retry-policy.js";
|
|
31
|
-
import {
|
|
31
|
+
import {
|
|
32
|
+
normalizeHttpRequestBody,
|
|
33
|
+
redactSensitiveError,
|
|
34
|
+
redactSensitiveRequestError,
|
|
35
|
+
type SerializedRequestUrl,
|
|
36
|
+
serializeRequestUrl,
|
|
37
|
+
} from "./request-options.js";
|
|
32
38
|
|
|
33
39
|
const DEFAULT_HTTP_BASE_URL = "http://localhost";
|
|
34
40
|
|
|
@@ -208,9 +214,58 @@ function requireNativeResponseBody(response: Response): ReadableStream<Uint8Arra
|
|
|
208
214
|
return response.body;
|
|
209
215
|
}
|
|
210
216
|
|
|
211
|
-
function
|
|
217
|
+
function sanitizeStreamErrors(
|
|
218
|
+
body: ReadableStream<Uint8Array>,
|
|
219
|
+
serializedUrl: SerializedRequestUrl,
|
|
220
|
+
): ReadableStream<Uint8Array> {
|
|
221
|
+
if (serializedUrl.sensitiveValues.length === 0) return body;
|
|
222
|
+
|
|
223
|
+
let reader: ReadableStreamDefaultReader<Uint8Array> | undefined;
|
|
224
|
+
return new ReadableStream<Uint8Array>(
|
|
225
|
+
{
|
|
226
|
+
async pull(controller) {
|
|
227
|
+
try {
|
|
228
|
+
reader ??= body.getReader();
|
|
229
|
+
const chunk = await reader.read();
|
|
230
|
+
if (chunk.done) {
|
|
231
|
+
controller.close();
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
controller.enqueue(chunk.value);
|
|
235
|
+
} catch (error) {
|
|
236
|
+
controller.error(
|
|
237
|
+
redactSensitiveError(
|
|
238
|
+
error,
|
|
239
|
+
serializedUrl.sensitiveValues,
|
|
240
|
+
serializedUrl.requestUrl,
|
|
241
|
+
serializedUrl.redactedUrl,
|
|
242
|
+
),
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
async cancel(reason) {
|
|
247
|
+
try {
|
|
248
|
+
await (reader ? reader.cancel(reason) : body.cancel(reason));
|
|
249
|
+
} catch (error) {
|
|
250
|
+
throw redactSensitiveError(
|
|
251
|
+
error,
|
|
252
|
+
serializedUrl.sensitiveValues,
|
|
253
|
+
serializedUrl.requestUrl,
|
|
254
|
+
serializedUrl.redactedUrl,
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
{ highWaterMark: 0 },
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function toNativeHttpStreamResponse(
|
|
264
|
+
response: Response,
|
|
265
|
+
serializedUrl: SerializedRequestUrl,
|
|
266
|
+
): HttpStreamResponse {
|
|
212
267
|
const headers = Object.fromEntries(response.headers.entries());
|
|
213
|
-
const body = requireNativeResponseBody(response);
|
|
268
|
+
const body = sanitizeStreamErrors(requireNativeResponseBody(response), serializedUrl);
|
|
214
269
|
return {
|
|
215
270
|
body,
|
|
216
271
|
headers,
|
|
@@ -305,6 +360,22 @@ function normalizeNativeFetchBody(body: unknown): string | ArrayBuffer | undefin
|
|
|
305
360
|
return copied.buffer;
|
|
306
361
|
}
|
|
307
362
|
|
|
363
|
+
function serializeHttpRequestUrl(
|
|
364
|
+
baseUrl: string | undefined,
|
|
365
|
+
url: string,
|
|
366
|
+
options: RequestOptions,
|
|
367
|
+
): SerializedRequestUrl {
|
|
368
|
+
try {
|
|
369
|
+
return serializeRequestUrl(
|
|
370
|
+
resolveHttpUrl(baseUrl, url),
|
|
371
|
+
options.params,
|
|
372
|
+
options.sensitiveParams,
|
|
373
|
+
);
|
|
374
|
+
} catch (error) {
|
|
375
|
+
throw redactSensitiveRequestError(error, url, options.sensitiveParams);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
308
379
|
async function fetchNativeHttp(
|
|
309
380
|
baseUrl: string | undefined,
|
|
310
381
|
url: string,
|
|
@@ -316,7 +387,8 @@ async function fetchNativeHttp(
|
|
|
316
387
|
proxyAttemptOffset = 0,
|
|
317
388
|
dedupe?: { attempted: Set<string> },
|
|
318
389
|
): Promise<NativeHttpAttemptOutcome> {
|
|
319
|
-
const
|
|
390
|
+
const serializedUrl = serializeHttpRequestUrl(baseUrl, url, options);
|
|
391
|
+
const { requestUrl } = serializedUrl;
|
|
320
392
|
const controller = options.timeout ? new AbortController() : undefined;
|
|
321
393
|
const timeoutHandle = options.timeout
|
|
322
394
|
? setTimeout(() => controller?.abort(), options.timeout)
|
|
@@ -374,9 +446,19 @@ async function fetchNativeHttp(
|
|
|
374
446
|
return toNativeHttpResponse(response);
|
|
375
447
|
} catch (error) {
|
|
376
448
|
if (error instanceof SyntaxError) {
|
|
377
|
-
throw
|
|
449
|
+
throw redactSensitiveError(
|
|
450
|
+
error,
|
|
451
|
+
serializedUrl.sensitiveValues,
|
|
452
|
+
serializedUrl.requestUrl,
|
|
453
|
+
serializedUrl.redactedUrl,
|
|
454
|
+
);
|
|
378
455
|
}
|
|
379
|
-
const transportError =
|
|
456
|
+
const transportError: NativeHttpAttemptError = redactSensitiveError(
|
|
457
|
+
toHttpTransportError(error),
|
|
458
|
+
serializedUrl.sensitiveValues,
|
|
459
|
+
serializedUrl.requestUrl,
|
|
460
|
+
serializedUrl.redactedUrl,
|
|
461
|
+
);
|
|
380
462
|
transportError.proxyUsed = Boolean(proxy);
|
|
381
463
|
throw transportError;
|
|
382
464
|
} finally {
|
|
@@ -392,7 +474,8 @@ async function fetchNativeHttpStream(
|
|
|
392
474
|
clientOptions: HttpClientOptions,
|
|
393
475
|
warn: (message: string) => void,
|
|
394
476
|
): Promise<HttpStreamResponse> {
|
|
395
|
-
const
|
|
477
|
+
const serializedUrl = serializeHttpRequestUrl(baseUrl, url, options);
|
|
478
|
+
const { requestUrl } = serializedUrl;
|
|
396
479
|
const controller = options.timeout ? new AbortController() : undefined;
|
|
397
480
|
const timeoutHandle = options.timeout
|
|
398
481
|
? setTimeout(() => controller?.abort(), options.timeout)
|
|
@@ -421,12 +504,22 @@ async function fetchNativeHttpStream(
|
|
|
421
504
|
});
|
|
422
505
|
}
|
|
423
506
|
|
|
424
|
-
return toNativeHttpStreamResponse(response);
|
|
507
|
+
return toNativeHttpStreamResponse(response, serializedUrl);
|
|
425
508
|
} catch (error) {
|
|
426
509
|
if (error instanceof SyntaxError) {
|
|
427
|
-
throw
|
|
510
|
+
throw redactSensitiveError(
|
|
511
|
+
error,
|
|
512
|
+
serializedUrl.sensitiveValues,
|
|
513
|
+
serializedUrl.requestUrl,
|
|
514
|
+
serializedUrl.redactedUrl,
|
|
515
|
+
);
|
|
428
516
|
}
|
|
429
|
-
throw
|
|
517
|
+
throw redactSensitiveError(
|
|
518
|
+
toHttpTransportError(error),
|
|
519
|
+
serializedUrl.sensitiveValues,
|
|
520
|
+
serializedUrl.requestUrl,
|
|
521
|
+
serializedUrl.redactedUrl,
|
|
522
|
+
);
|
|
430
523
|
} finally {
|
|
431
524
|
if (timeoutHandle) clearTimeout(timeoutHandle);
|
|
432
525
|
}
|
|
@@ -451,22 +544,29 @@ export function createHttpClient(
|
|
|
451
544
|
method: string,
|
|
452
545
|
options: RequestOptions & { body?: unknown } = {},
|
|
453
546
|
): Promise<HttpResponse> {
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
547
|
+
const { explicitRetry, headersOptions, methodName, retryOptions } = (() => {
|
|
548
|
+
try {
|
|
549
|
+
if (!baseUrl && !isAbsoluteUrl(url)) {
|
|
550
|
+
throw new TransportError(
|
|
551
|
+
"ctx.http requires an absolute URL when provider.upstream.baseUrl is not declared",
|
|
552
|
+
{ code: "transport_invalid_url" },
|
|
553
|
+
);
|
|
554
|
+
}
|
|
555
|
+
assertNoHttpTransportOverrides(options);
|
|
556
|
+
const headersOptions = withClientHeaders(options, clientOptions, options.body);
|
|
557
|
+
const methodName = normalizeHttpMethod(method);
|
|
558
|
+
const explicitRetry = headersOptions.retry !== undefined;
|
|
559
|
+
const retryOptions =
|
|
560
|
+
normalizeProxyTransportRetryOptions(headersOptions.retry, {
|
|
561
|
+
label: "HTTP",
|
|
562
|
+
}) ??
|
|
563
|
+
(explicitRetry ? undefined : createDefaultProxyTransportRetryOptions({ label: "HTTP" }));
|
|
564
|
+
if (retryOptions) validateUnsafeProxyTransportRetryMethods(retryOptions, "HTTP");
|
|
565
|
+
return { explicitRetry, headersOptions, methodName, retryOptions };
|
|
566
|
+
} catch (error) {
|
|
567
|
+
throw redactSensitiveRequestError(error, url, options.sensitiveParams);
|
|
568
|
+
}
|
|
569
|
+
})();
|
|
470
570
|
const retryEnabled = Boolean(
|
|
471
571
|
retryOptions &&
|
|
472
572
|
retryOptions.attempts > 1 &&
|
|
@@ -531,9 +631,7 @@ export function createHttpClient(
|
|
|
531
631
|
explicitRetry,
|
|
532
632
|
method: methodName,
|
|
533
633
|
});
|
|
534
|
-
const dedupeContext = dedupeAllocatorEndpoints
|
|
535
|
-
? { attempted: new Set<string>() }
|
|
536
|
-
: undefined;
|
|
634
|
+
const dedupeContext = dedupeAllocatorEndpoints ? { attempted: new Set<string>() } : undefined;
|
|
537
635
|
|
|
538
636
|
const executeOnce = (proxyAttemptOffset = 0): Promise<NativeHttpAttemptOutcome> =>
|
|
539
637
|
fetchNativeHttp(
|
|
@@ -654,15 +752,23 @@ export function createHttpClient(
|
|
|
654
752
|
method: string,
|
|
655
753
|
options: RequestOptions & { body?: unknown } = {},
|
|
656
754
|
): Promise<HttpStreamResponse> {
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
755
|
+
const { headersOptions, methodName } = (() => {
|
|
756
|
+
try {
|
|
757
|
+
if (!baseUrl && !isAbsoluteUrl(url)) {
|
|
758
|
+
throw new TransportError(
|
|
759
|
+
"ctx.http requires an absolute URL when provider.upstream.baseUrl is not declared",
|
|
760
|
+
{ code: "transport_invalid_url" },
|
|
761
|
+
);
|
|
762
|
+
}
|
|
763
|
+
assertNoHttpTransportOverrides(options);
|
|
764
|
+
return {
|
|
765
|
+
headersOptions: withClientHeaders(options, clientOptions, options.body),
|
|
766
|
+
methodName: normalizeHttpMethod(method),
|
|
767
|
+
};
|
|
768
|
+
} catch (error) {
|
|
769
|
+
throw redactSensitiveRequestError(error, url, options.sensitiveParams);
|
|
770
|
+
}
|
|
771
|
+
})();
|
|
666
772
|
return fetchNativeHttpStream(baseUrl, url, methodName, headersOptions, clientOptions, warnOnce);
|
|
667
773
|
}
|
|
668
774
|
|