@apifuse/provider-sdk 2.1.0-beta.0 → 2.1.0-beta.10
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 +218 -21
- package/CHANGELOG.md +54 -0
- package/README.md +147 -10
- package/SUBMISSION.md +87 -0
- package/bin/apifuse-check.ts +86 -4
- package/bin/apifuse-dev.ts +87 -13
- package/bin/apifuse-pack-check.ts +120 -0
- package/bin/apifuse-pack-smoke.ts +423 -0
- package/bin/apifuse-perf.ts +142 -49
- package/bin/apifuse-record.ts +182 -104
- package/bin/apifuse-submit-check.ts +2538 -0
- package/bin/apifuse.ts +1 -1
- package/dist/ceremonies/index.d.ts +41 -0
- package/dist/ceremonies/index.js +490 -0
- package/dist/choice-token.d.ts +24 -0
- package/dist/choice-token.js +74 -0
- package/dist/cli/commands.d.ts +10 -0
- package/dist/cli/commands.js +80 -0
- package/dist/cli/create.d.ts +47 -0
- package/dist/cli/create.js +762 -0
- package/dist/cli/templates/provider/.dockerignore.tpl +22 -0
- package/dist/cli/templates/provider/.gitignore.tpl +22 -0
- package/dist/cli/templates/provider/Dockerfile.tpl +7 -0
- package/dist/cli/templates/provider/README.md.tpl +160 -0
- package/dist/cli/templates/provider/dev.ts.tpl +5 -0
- package/dist/cli/templates/provider/domain/README.md.tpl +3 -0
- package/dist/cli/templates/provider/index.test.ts.tpl +13 -0
- package/dist/cli/templates/provider/index.ts.tpl +15 -0
- package/dist/cli/templates/provider/mappers/README.md.tpl +3 -0
- package/dist/cli/templates/provider/meta.ts.tpl +7 -0
- package/dist/cli/templates/provider/operations/index.ts.tpl +5 -0
- package/dist/cli/templates/provider/operations/ping.ts.tpl +24 -0
- package/dist/cli/templates/provider/schemas/ping.ts.tpl +24 -0
- package/dist/cli/templates/provider/start.ts.tpl +5 -0
- package/dist/cli/templates/provider/upstream/README.md.tpl +3 -0
- package/dist/config/loader.d.ts +107 -0
- package/dist/config/loader.js +935 -0
- package/dist/contract-json.d.ts +9 -0
- package/dist/contract-json.js +51 -0
- package/dist/contract-serialization.d.ts +4 -0
- package/dist/contract-serialization.js +78 -0
- package/dist/contract-types.d.ts +49 -0
- package/dist/contract-types.js +1 -0
- package/dist/contract.d.ts +6 -0
- package/dist/contract.js +155 -0
- package/dist/define.d.ts +97 -0
- package/dist/define.js +1320 -0
- package/dist/dev.d.ts +9 -0
- package/dist/dev.js +15 -0
- package/dist/errors.d.ts +59 -0
- package/dist/errors.js +97 -0
- package/dist/i18n/catalog.d.ts +29 -0
- package/dist/i18n/catalog.js +159 -0
- package/dist/i18n/index.d.ts +2 -0
- package/dist/i18n/index.js +2 -0
- package/dist/i18n/keys.d.ts +10 -0
- package/dist/i18n/keys.js +34 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +37 -0
- package/dist/lint.d.ts +73 -0
- package/dist/lint.js +702 -0
- package/dist/observability.d.ts +5 -0
- package/dist/observability.js +39 -0
- package/dist/provider.d.ts +9 -0
- package/dist/provider.js +8 -0
- package/dist/public-schema-field-lint.d.ts +2 -0
- package/dist/public-schema-field-lint.js +158 -0
- package/dist/recipes/gov-api.d.ts +19 -0
- package/dist/recipes/gov-api.js +72 -0
- package/dist/recipes/rest-api.d.ts +21 -0
- package/dist/recipes/rest-api.js +115 -0
- package/dist/runtime/auth-flow.d.ts +14 -0
- package/dist/runtime/auth-flow.js +44 -0
- package/dist/runtime/browser.d.ts +25 -0
- package/dist/runtime/browser.js +1034 -0
- package/dist/runtime/cache.d.ts +10 -0
- package/dist/runtime/cache.js +372 -0
- package/dist/runtime/choice.d.ts +15 -0
- package/dist/runtime/choice.js +435 -0
- package/dist/runtime/credential.d.ts +8 -0
- package/dist/runtime/credential.js +61 -0
- package/dist/runtime/env.d.ts +2 -0
- package/dist/runtime/env.js +10 -0
- package/dist/runtime/executor.d.ts +16 -0
- package/dist/runtime/executor.js +51 -0
- package/dist/runtime/http.d.ts +8 -0
- package/dist/runtime/http.js +706 -0
- package/dist/runtime/insights.d.ts +9 -0
- package/dist/runtime/insights.js +324 -0
- package/dist/runtime/instrumentation.d.ts +8 -0
- package/dist/runtime/instrumentation.js +269 -0
- package/dist/runtime/key-derivation.d.ts +24 -0
- package/dist/runtime/key-derivation.js +73 -0
- package/dist/runtime/keyring.d.ts +25 -0
- package/dist/runtime/keyring.js +93 -0
- package/dist/runtime/namespace.d.ts +9 -0
- package/dist/runtime/namespace.js +19 -0
- package/dist/runtime/otlp.d.ts +39 -0
- package/dist/runtime/otlp.js +103 -0
- package/dist/runtime/perf.d.ts +12 -0
- package/dist/runtime/perf.js +52 -0
- package/dist/runtime/prevalidate.d.ts +12 -0
- package/dist/runtime/prevalidate.js +173 -0
- package/dist/runtime/provider.d.ts +2 -0
- package/dist/runtime/provider.js +11 -0
- package/dist/runtime/proxy-errors.d.ts +21 -0
- package/dist/runtime/proxy-errors.js +83 -0
- package/dist/runtime/proxy-telemetry.d.ts +8 -0
- package/dist/runtime/proxy-telemetry.js +174 -0
- package/dist/runtime/redis.d.ts +17 -0
- package/dist/runtime/redis.js +82 -0
- package/dist/runtime/request-options.d.ts +3 -0
- package/dist/runtime/request-options.js +42 -0
- package/dist/runtime/state.d.ts +17 -0
- package/dist/runtime/state.js +344 -0
- package/dist/runtime/stealth.d.ts +18 -0
- package/dist/runtime/stealth.js +834 -0
- package/dist/runtime/stt.d.ts +22 -0
- package/dist/runtime/stt.js +480 -0
- package/dist/runtime/trace.d.ts +26 -0
- package/dist/runtime/trace.js +142 -0
- package/dist/runtime/waterfall.d.ts +12 -0
- package/dist/runtime/waterfall.js +147 -0
- package/dist/schema.d.ts +74 -0
- package/dist/schema.js +243 -0
- package/dist/serve.d.ts +1 -0
- package/dist/serve.js +1 -0
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.js +2 -0
- package/dist/server/serve.d.ts +64 -0
- package/dist/server/serve.js +1110 -0
- package/dist/server/types.d.ts +136 -0
- package/dist/server/types.js +86 -0
- package/dist/stealth/profiles.d.ts +4 -0
- package/dist/stealth/profiles.js +259 -0
- package/dist/stream.d.ts +44 -0
- package/dist/stream.js +151 -0
- package/dist/testing/helpers.d.ts +23 -0
- package/dist/testing/helpers.js +95 -0
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.js +2 -0
- package/dist/testing/run.d.ts +34 -0
- package/dist/testing/run.js +303 -0
- package/dist/types.d.ts +1326 -0
- package/dist/types.js +61 -0
- package/dist/utils/date.d.ts +6 -0
- package/dist/utils/date.js +101 -0
- package/dist/utils/parse.d.ts +16 -0
- package/dist/utils/parse.js +51 -0
- package/dist/utils/text.d.ts +4 -0
- package/dist/utils/text.js +14 -0
- package/dist/utils/transform.d.ts +8 -0
- package/dist/utils/transform.js +48 -0
- package/package.json +57 -29
- package/src/ceremonies/index.ts +30 -3
- package/src/choice-token.ts +165 -0
- package/src/cli/commands.ts +34 -11
- package/src/cli/create.ts +214 -52
- package/src/cli/templates/provider/.dockerignore.tpl +22 -0
- package/src/cli/templates/provider/.gitignore.tpl +22 -0
- package/src/cli/templates/provider/README.md.tpl +134 -2
- package/src/cli/templates/provider/dev.ts.tpl +1 -1
- package/src/cli/templates/provider/domain/README.md.tpl +3 -0
- package/src/cli/templates/provider/index.ts.tpl +5 -44
- package/src/cli/templates/provider/mappers/README.md.tpl +3 -0
- package/src/cli/templates/provider/meta.ts.tpl +7 -0
- package/src/cli/templates/provider/operations/index.ts.tpl +5 -0
- package/src/cli/templates/provider/operations/ping.ts.tpl +24 -0
- package/src/cli/templates/provider/schemas/ping.ts.tpl +24 -0
- package/src/cli/templates/provider/start.ts.tpl +1 -1
- package/src/cli/templates/provider/upstream/README.md.tpl +3 -0
- package/src/config/loader.ts +1282 -7
- package/src/contract-json.ts +75 -0
- package/src/contract-serialization.ts +89 -0
- package/src/contract-types.ts +52 -0
- package/src/contract.ts +215 -0
- package/src/define.ts +1726 -48
- package/src/errors.ts +27 -0
- package/src/i18n/catalog.ts +277 -0
- package/src/i18n/index.ts +2 -0
- package/src/i18n/keys.ts +64 -0
- package/src/index.ts +174 -15
- package/src/lint.ts +547 -73
- package/src/observability.ts +41 -0
- package/src/provider.ts +104 -5
- package/src/public-schema-field-lint.ts +237 -0
- package/src/runtime/auth-flow.ts +7 -0
- package/src/runtime/browser.ts +762 -51
- package/src/runtime/cache.ts +528 -0
- package/src/runtime/choice.ts +760 -0
- package/src/runtime/executor.ts +32 -3
- package/src/runtime/http.ts +945 -185
- package/src/runtime/insights.ts +11 -11
- package/src/runtime/instrumentation.ts +12 -4
- package/src/runtime/key-derivation.ts +1 -1
- package/src/runtime/keyring.ts +4 -3
- package/src/runtime/proxy-errors.ts +132 -0
- package/src/runtime/proxy-telemetry.ts +253 -0
- package/src/runtime/redis.ts +116 -0
- package/src/runtime/request-options.ts +66 -0
- package/src/runtime/state.ts +563 -0
- package/src/runtime/stealth.ts +1159 -0
- package/src/runtime/stt.ts +629 -0
- package/src/runtime/trace.ts +1 -1
- package/src/schema.ts +363 -1
- package/src/server/serve.ts +1172 -76
- package/src/server/types.ts +37 -0
- package/src/stream.ts +210 -0
- package/src/testing/run.ts +31 -5
- package/src/types.ts +1118 -44
- package/src/composite.ts +0 -43
- package/src/runtime/tls.ts +0 -425
- package/src/types/playwright-stealth.d.ts +0 -9
package/bin/apifuse-perf.ts
CHANGED
|
@@ -8,8 +8,11 @@ import { pathToFileURL } from "node:url";
|
|
|
8
8
|
|
|
9
9
|
import {
|
|
10
10
|
type ApiFuseConfig,
|
|
11
|
+
createBypassProviderCache,
|
|
11
12
|
createHttpClient,
|
|
12
|
-
|
|
13
|
+
createProviderChoiceContext,
|
|
14
|
+
createStealthClient,
|
|
15
|
+
createSttClientFromEnv,
|
|
13
16
|
executeOperation,
|
|
14
17
|
getProviderBaseUrl,
|
|
15
18
|
type HttpClient,
|
|
@@ -18,8 +21,8 @@ import {
|
|
|
18
21
|
type ProviderDefinition,
|
|
19
22
|
ProviderError,
|
|
20
23
|
type Span,
|
|
21
|
-
type
|
|
22
|
-
type
|
|
24
|
+
type StealthClient,
|
|
25
|
+
type StealthResponse,
|
|
23
26
|
wrapWithInstrumentation,
|
|
24
27
|
} from "../src";
|
|
25
28
|
import {
|
|
@@ -27,6 +30,7 @@ import {
|
|
|
27
30
|
groupSpansByName,
|
|
28
31
|
type PerfStats,
|
|
29
32
|
} from "../src/runtime/perf";
|
|
33
|
+
import { createMemoryProviderRuntimeState } from "../src/runtime/state";
|
|
30
34
|
import {
|
|
31
35
|
createTraceContext,
|
|
32
36
|
resolveTraceContextOptions,
|
|
@@ -41,6 +45,7 @@ type CliArgs = {
|
|
|
41
45
|
exportPath?: string;
|
|
42
46
|
flame: boolean;
|
|
43
47
|
operation: string;
|
|
48
|
+
params?: string;
|
|
44
49
|
runs: number;
|
|
45
50
|
warmup: number;
|
|
46
51
|
};
|
|
@@ -79,6 +84,21 @@ const DEFAULT_RUNS = 10;
|
|
|
79
84
|
const DEFAULT_WARMUP = 2;
|
|
80
85
|
const DEFAULT_CONCURRENCY = 1;
|
|
81
86
|
const BAR_WIDTH = 20;
|
|
87
|
+
const HELP_TEXT = `Usage: apifuse perf <provider-path> --operation <operation> [options]
|
|
88
|
+
|
|
89
|
+
Options:
|
|
90
|
+
--operation, -o <name> operation to profile (required)
|
|
91
|
+
--params, -p <json> JSON input template; falls back to fixtures.request or {}
|
|
92
|
+
--runs, -n <number> number of runs (default: 10)
|
|
93
|
+
--warmup <number> warmup runs (default: 2)
|
|
94
|
+
--concurrency, -c <n> concurrent requests (default: 1)
|
|
95
|
+
--compare-proxy run with proxy on/off and compare
|
|
96
|
+
--export <path> export results to JSON file
|
|
97
|
+
--flame generate flamegraph SVG
|
|
98
|
+
--help, -h show this help
|
|
99
|
+
|
|
100
|
+
Example:
|
|
101
|
+
apifuse perf providers/korea-air-quality --operation realtime --params '{"stationName":"jongno"}' --runs 5`;
|
|
82
102
|
|
|
83
103
|
export async function main() {
|
|
84
104
|
try {
|
|
@@ -92,7 +112,11 @@ export async function main() {
|
|
|
92
112
|
const inputSchema = getOperationSchema(provider, operation, "input");
|
|
93
113
|
const outputSchema = getOperationSchema(provider, operation, "output");
|
|
94
114
|
const fixtureReplay = await loadFixtureReplay(providerDirectory);
|
|
95
|
-
const inputTemplate = resolveInputTemplate(
|
|
115
|
+
const inputTemplate = resolveInputTemplate(
|
|
116
|
+
provider,
|
|
117
|
+
inputSchema,
|
|
118
|
+
args.params,
|
|
119
|
+
);
|
|
96
120
|
|
|
97
121
|
const directSuite = await runProfileSuite({
|
|
98
122
|
args,
|
|
@@ -182,6 +206,7 @@ function parseArgs(argv: string[]): CliArgs {
|
|
|
182
206
|
let compareProxy = false;
|
|
183
207
|
let exportPath: string | undefined;
|
|
184
208
|
let flame = false;
|
|
209
|
+
let params: string | undefined;
|
|
185
210
|
|
|
186
211
|
for (let index = 0; index < argv.length; index += 1) {
|
|
187
212
|
const arg = argv[index];
|
|
@@ -199,6 +224,11 @@ function parseArgs(argv: string[]): CliArgs {
|
|
|
199
224
|
continue;
|
|
200
225
|
}
|
|
201
226
|
|
|
227
|
+
if (arg === "--help" || arg === "-h") {
|
|
228
|
+
console.log(HELP_TEXT);
|
|
229
|
+
process.exit(0);
|
|
230
|
+
}
|
|
231
|
+
|
|
202
232
|
if (arg === "--compare-proxy") {
|
|
203
233
|
compareProxy = true;
|
|
204
234
|
continue;
|
|
@@ -220,6 +250,22 @@ function parseArgs(argv: string[]): CliArgs {
|
|
|
220
250
|
continue;
|
|
221
251
|
}
|
|
222
252
|
|
|
253
|
+
if (arg === "--params" || arg === "-p") {
|
|
254
|
+
params = requireArgValue(argv, index, arg);
|
|
255
|
+
index += 1;
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if (arg.startsWith("--params=")) {
|
|
260
|
+
params = arg.slice("--params=".length);
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (arg.startsWith("-p=")) {
|
|
265
|
+
params = arg.slice("-p=".length);
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
|
|
223
269
|
if (arg.startsWith("-o=")) {
|
|
224
270
|
operation = arg.slice("-o=".length);
|
|
225
271
|
continue;
|
|
@@ -292,20 +338,7 @@ function parseArgs(argv: string[]): CliArgs {
|
|
|
292
338
|
}
|
|
293
339
|
|
|
294
340
|
if (!providerPath || !operation) {
|
|
295
|
-
throw new Error(
|
|
296
|
-
[
|
|
297
|
-
"Usage: apifuse perf <provider-path> [options]",
|
|
298
|
-
"",
|
|
299
|
-
"Options:",
|
|
300
|
-
" --operation, -o <name> operation to profile (required)",
|
|
301
|
-
" --runs, -n <number> number of runs (default: 10)",
|
|
302
|
-
" --warmup <number> warmup runs (default: 2)",
|
|
303
|
-
" --concurrency, -c <n> concurrent requests (default: 1)",
|
|
304
|
-
" --compare-proxy run with proxy on/off and compare",
|
|
305
|
-
" --export <path> export results to JSON file",
|
|
306
|
-
" --flame generate flamegraph SVG",
|
|
307
|
-
].join("\n"),
|
|
308
|
-
);
|
|
341
|
+
throw new Error(HELP_TEXT);
|
|
309
342
|
}
|
|
310
343
|
|
|
311
344
|
return {
|
|
@@ -315,6 +348,7 @@ function parseArgs(argv: string[]): CliArgs {
|
|
|
315
348
|
exportPath,
|
|
316
349
|
flame,
|
|
317
350
|
operation,
|
|
351
|
+
params,
|
|
318
352
|
runs,
|
|
319
353
|
warmup,
|
|
320
354
|
};
|
|
@@ -409,7 +443,18 @@ function isSchema(value: unknown): value is { parse(input: unknown): unknown } {
|
|
|
409
443
|
function resolveInputTemplate(
|
|
410
444
|
provider: ProviderDefinition,
|
|
411
445
|
inputSchema: { parse(input: unknown): unknown },
|
|
446
|
+
params: string | undefined,
|
|
412
447
|
): unknown {
|
|
448
|
+
if (params !== undefined) {
|
|
449
|
+
try {
|
|
450
|
+
return inputSchema.parse(JSON.parse(params));
|
|
451
|
+
} catch (error) {
|
|
452
|
+
throw new Error(
|
|
453
|
+
`Failed to parse --params JSON or validate input: ${error instanceof Error ? error.message : String(error)}`,
|
|
454
|
+
);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
413
458
|
const firstOp = Object.values(provider.operations)[0];
|
|
414
459
|
if (firstOp?.fixtures?.request !== undefined) {
|
|
415
460
|
return firstOp.fixtures.request;
|
|
@@ -440,12 +485,12 @@ async function loadFixtureReplay(
|
|
|
440
485
|
}
|
|
441
486
|
|
|
442
487
|
function assertProxyConfigured(config: ApiFuseConfig): void {
|
|
443
|
-
if (config.proxy?.url || process.env.
|
|
488
|
+
if (config.proxy?.url || process.env.APIFUSE__PROXY__URL) {
|
|
444
489
|
return;
|
|
445
490
|
}
|
|
446
491
|
|
|
447
492
|
throw new Error(
|
|
448
|
-
"--compare-proxy requires a proxy URL in apifuse.config.ts or
|
|
493
|
+
"--compare-proxy requires a proxy URL in apifuse.config.ts or APIFUSE__PROXY__URL.",
|
|
449
494
|
);
|
|
450
495
|
}
|
|
451
496
|
|
|
@@ -637,30 +682,44 @@ function createBaseContext(options: {
|
|
|
637
682
|
apifuseConfig,
|
|
638
683
|
upstream,
|
|
639
684
|
});
|
|
640
|
-
const
|
|
685
|
+
const stealth =
|
|
641
686
|
options.forceFixtureReplay && options.fixtureReplay
|
|
642
|
-
?
|
|
643
|
-
:
|
|
687
|
+
? createFixtureStealthClient(options.fixtureReplay.rawText)
|
|
688
|
+
: createStealthClient(getProviderBaseUrl(options.provider), {
|
|
644
689
|
apifuseConfig,
|
|
645
690
|
upstream,
|
|
646
691
|
});
|
|
647
692
|
|
|
693
|
+
const env = {
|
|
694
|
+
get: (key: string) => process.env[key],
|
|
695
|
+
};
|
|
696
|
+
const credential = {
|
|
697
|
+
mode: "none" as const,
|
|
698
|
+
get: () => undefined,
|
|
699
|
+
getAll: () => ({}),
|
|
700
|
+
getAccessToken: () => undefined,
|
|
701
|
+
getScopes: () => [],
|
|
702
|
+
};
|
|
703
|
+
const state = createMemoryProviderRuntimeState();
|
|
648
704
|
return {
|
|
649
|
-
env
|
|
650
|
-
|
|
651
|
-
},
|
|
652
|
-
credential: {
|
|
653
|
-
mode: "none",
|
|
654
|
-
get: () => undefined,
|
|
655
|
-
getAll: () => ({}),
|
|
656
|
-
getAccessToken: () => undefined,
|
|
657
|
-
getScopes: () => [],
|
|
658
|
-
},
|
|
705
|
+
env,
|
|
706
|
+
credential,
|
|
707
|
+
request: { headers: {} },
|
|
659
708
|
http,
|
|
660
|
-
|
|
709
|
+
cache: createBypassProviderCache({ providerId: options.provider.id }),
|
|
710
|
+
state,
|
|
711
|
+
stealth,
|
|
661
712
|
browser: createBrowserStub(),
|
|
662
713
|
trace: options.traceContext,
|
|
663
714
|
auth: createAuthStub(),
|
|
715
|
+
stt: createSttClientFromEnv(options.provider.stt),
|
|
716
|
+
choice: createProviderChoiceContext({
|
|
717
|
+
providerId: options.provider.id,
|
|
718
|
+
env,
|
|
719
|
+
request: { headers: {} },
|
|
720
|
+
credential,
|
|
721
|
+
state,
|
|
722
|
+
}),
|
|
664
723
|
};
|
|
665
724
|
}
|
|
666
725
|
|
|
@@ -695,16 +754,25 @@ function createFixtureResponse(raw: unknown) {
|
|
|
695
754
|
};
|
|
696
755
|
}
|
|
697
756
|
|
|
698
|
-
function
|
|
699
|
-
const createResponse = async (): Promise<
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
757
|
+
function createFixtureStealthClient(rawText: string): StealthClient {
|
|
758
|
+
const createResponse = async (): Promise<StealthResponse> => {
|
|
759
|
+
const bodyBytes = new TextEncoder().encode(rawText);
|
|
760
|
+
return {
|
|
761
|
+
status: 200,
|
|
762
|
+
ok: true,
|
|
763
|
+
headers: { "content-type": "application/json" },
|
|
764
|
+
rawHeaders: [["content-type", "application/json"]],
|
|
765
|
+
body: rawText,
|
|
766
|
+
cookies: { get: () => undefined, getAll: () => ({}), toString: () => "" },
|
|
767
|
+
json: async <T>() => JSON.parse(rawText) as T,
|
|
768
|
+
arrayBuffer: async () =>
|
|
769
|
+
bodyBytes.buffer.slice(
|
|
770
|
+
bodyBytes.byteOffset,
|
|
771
|
+
bodyBytes.byteOffset + bodyBytes.byteLength,
|
|
772
|
+
) as ArrayBuffer,
|
|
773
|
+
bytes: async () => new Uint8Array(bodyBytes),
|
|
774
|
+
};
|
|
775
|
+
};
|
|
708
776
|
|
|
709
777
|
return {
|
|
710
778
|
fetch: async () => createResponse(),
|
|
@@ -720,6 +788,7 @@ function createFixtureTlsClient(rawText: string): TlsClient {
|
|
|
720
788
|
function createBrowserStub(): BrowserClient {
|
|
721
789
|
return {
|
|
722
790
|
engine: "playwright-stealth",
|
|
791
|
+
async close() {},
|
|
723
792
|
async newPage() {
|
|
724
793
|
throw new ProviderError(
|
|
725
794
|
"Browser runtime is not supported by apifuse perf yet.",
|
|
@@ -728,6 +797,30 @@ function createBrowserStub(): BrowserClient {
|
|
|
728
797
|
},
|
|
729
798
|
);
|
|
730
799
|
},
|
|
800
|
+
async rawPage() {
|
|
801
|
+
throw new ProviderError(
|
|
802
|
+
"Browser runtime is not supported by apifuse perf yet.",
|
|
803
|
+
{
|
|
804
|
+
code: "BROWSER_RUNTIME_UNSUPPORTED",
|
|
805
|
+
},
|
|
806
|
+
);
|
|
807
|
+
},
|
|
808
|
+
async withIsolatedContext() {
|
|
809
|
+
throw new ProviderError(
|
|
810
|
+
"Browser runtime is not supported by apifuse perf yet.",
|
|
811
|
+
{
|
|
812
|
+
code: "BROWSER_RUNTIME_UNSUPPORTED",
|
|
813
|
+
},
|
|
814
|
+
);
|
|
815
|
+
},
|
|
816
|
+
async solveChallenge() {
|
|
817
|
+
throw new ProviderError(
|
|
818
|
+
"Browser runtime is not supported by apifuse perf yet.",
|
|
819
|
+
{
|
|
820
|
+
code: "BROWSER_RUNTIME_UNSUPPORTED",
|
|
821
|
+
},
|
|
822
|
+
);
|
|
823
|
+
},
|
|
731
824
|
};
|
|
732
825
|
}
|
|
733
826
|
|
|
@@ -738,7 +831,7 @@ function buildInsights(
|
|
|
738
831
|
): string[] {
|
|
739
832
|
const insights: string[] = [];
|
|
740
833
|
const allSpans = runs.flatMap((run) => run.spans);
|
|
741
|
-
const
|
|
834
|
+
const stealthSpans = allSpans.filter((span) => span.name === "stealth.fetch");
|
|
742
835
|
const dnsSpans = allSpans.filter((span) => span.name === "dns");
|
|
743
836
|
const transform = breakdown.find(
|
|
744
837
|
(entry) => entry.name === "transformResponse",
|
|
@@ -746,7 +839,7 @@ function buildInsights(
|
|
|
746
839
|
const responseSizes = allSpans
|
|
747
840
|
.map((span) => span.attributes.response_size)
|
|
748
841
|
.filter((value): value is number => typeof value === "number");
|
|
749
|
-
const reuseFlags =
|
|
842
|
+
const reuseFlags = stealthSpans
|
|
750
843
|
.map((span) => span.attributes.connection_reused)
|
|
751
844
|
.filter((value): value is boolean => typeof value === "boolean");
|
|
752
845
|
|
|
@@ -756,8 +849,8 @@ function buildInsights(
|
|
|
756
849
|
);
|
|
757
850
|
insights.push(
|
|
758
851
|
reusePercent >= 80
|
|
759
|
-
? `✓
|
|
760
|
-
: `⚠
|
|
852
|
+
? `✓ Stealth connection reuse: ${reusePercent}% (good)`
|
|
853
|
+
: `⚠ Stealth connection reuse: ${reusePercent}% — consider session reuse`,
|
|
761
854
|
);
|
|
762
855
|
}
|
|
763
856
|
|
|
@@ -1091,7 +1184,7 @@ function cloneValue<T>(value: T): T {
|
|
|
1091
1184
|
|
|
1092
1185
|
function handleCliError(error: unknown): never {
|
|
1093
1186
|
const message = error instanceof Error ? error.message : String(error);
|
|
1094
|
-
console.error(message);
|
|
1187
|
+
console.error(`[apifuse perf] ${message}`);
|
|
1095
1188
|
process.exit(1);
|
|
1096
1189
|
}
|
|
1097
1190
|
|