@apifuse/provider-sdk 2.1.0-beta.3 → 2.1.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.
Files changed (60) hide show
  1. package/AUTHORING.md +163 -8
  2. package/CHANGELOG.md +8 -1
  3. package/README.md +17 -16
  4. package/SUBMISSION.md +4 -4
  5. package/bin/apifuse-dev.ts +12 -5
  6. package/bin/apifuse-pack-check.ts +9 -2
  7. package/bin/apifuse-pack-smoke.ts +127 -6
  8. package/bin/apifuse-perf.ts +19 -15
  9. package/bin/apifuse-record.ts +41 -53
  10. package/bin/apifuse-submit-check.ts +179 -7
  11. package/bin/apifuse.ts +1 -1
  12. package/package.json +17 -8
  13. package/src/choice-token.ts +164 -0
  14. package/src/cli/commands.ts +1 -3
  15. package/src/cli/create.ts +159 -50
  16. package/src/cli/templates/provider/README.md.tpl +24 -7
  17. package/src/cli/templates/provider/dev.ts.tpl +1 -1
  18. package/src/cli/templates/provider/domain/README.md.tpl +3 -0
  19. package/src/cli/templates/provider/index.ts.tpl +5 -47
  20. package/src/cli/templates/provider/mappers/README.md.tpl +3 -0
  21. package/src/cli/templates/provider/meta.ts.tpl +7 -0
  22. package/src/cli/templates/provider/operations/index.ts.tpl +5 -0
  23. package/src/cli/templates/provider/operations/ping.ts.tpl +23 -0
  24. package/src/cli/templates/provider/schemas/ping.ts.tpl +16 -0
  25. package/src/cli/templates/provider/start.ts.tpl +1 -1
  26. package/src/cli/templates/provider/upstream/README.md.tpl +3 -0
  27. package/src/config/loader.ts +1206 -9
  28. package/src/define.ts +1618 -104
  29. package/src/errors.ts +12 -0
  30. package/src/i18n/catalog.ts +121 -0
  31. package/src/i18n/index.ts +2 -0
  32. package/src/i18n/keys.ts +64 -0
  33. package/src/index.ts +149 -8
  34. package/src/lint.ts +297 -42
  35. package/src/observability.ts +41 -0
  36. package/src/provider.ts +60 -3
  37. package/src/public-schema-field-lint.ts +237 -0
  38. package/src/runtime/auth-flow.ts +7 -0
  39. package/src/runtime/browser.ts +77 -21
  40. package/src/runtime/cache.ts +582 -0
  41. package/src/runtime/executor.ts +13 -1
  42. package/src/runtime/http.ts +939 -195
  43. package/src/runtime/insights.ts +11 -11
  44. package/src/runtime/instrumentation.ts +12 -4
  45. package/src/runtime/key-derivation.ts +1 -1
  46. package/src/runtime/keyring.ts +4 -3
  47. package/src/runtime/proxy-errors.ts +132 -0
  48. package/src/runtime/proxy-telemetry.ts +253 -0
  49. package/src/runtime/request-options.ts +66 -0
  50. package/src/runtime/state.ts +76 -0
  51. package/src/runtime/stealth.ts +1145 -0
  52. package/src/runtime/stt.ts +629 -0
  53. package/src/schema.ts +363 -1
  54. package/src/server/serve.ts +816 -58
  55. package/src/server/types.ts +35 -0
  56. package/src/stream.ts +210 -0
  57. package/src/testing/run.ts +17 -4
  58. package/src/types.ts +869 -50
  59. package/src/runtime/tls.ts +0 -434
  60. package/src/types/playwright-stealth.d.ts +0 -9
@@ -8,8 +8,10 @@ import { pathToFileURL } from "node:url";
8
8
 
9
9
  import {
10
10
  type ApiFuseConfig,
11
+ createBypassProviderCache,
11
12
  createHttpClient,
12
- createTlsClient,
13
+ createStealthClient,
14
+ createSttClientFromEnv,
13
15
  executeOperation,
14
16
  getProviderBaseUrl,
15
17
  type HttpClient,
@@ -18,8 +20,8 @@ import {
18
20
  type ProviderDefinition,
19
21
  ProviderError,
20
22
  type Span,
21
- type TlsClient,
22
- type TlsResponse,
23
+ type StealthClient,
24
+ type StealthResponse,
23
25
  wrapWithInstrumentation,
24
26
  } from "../src";
25
27
  import {
@@ -440,12 +442,12 @@ async function loadFixtureReplay(
440
442
  }
441
443
 
442
444
  function assertProxyConfigured(config: ApiFuseConfig): void {
443
- if (config.proxy?.url || process.env.APIFUSE_PROXY_URL) {
445
+ if (config.proxy?.url || process.env.APIFUSE__PROXY__URL) {
444
446
  return;
445
447
  }
446
448
 
447
449
  throw new Error(
448
- "--compare-proxy requires a proxy URL in apifuse.config.ts or APIFUSE_PROXY_URL.",
450
+ "--compare-proxy requires a proxy URL in apifuse.config.ts or APIFUSE__PROXY__URL.",
449
451
  );
450
452
  }
451
453
 
@@ -637,10 +639,10 @@ function createBaseContext(options: {
637
639
  apifuseConfig,
638
640
  upstream,
639
641
  });
640
- const tls =
642
+ const stealth =
641
643
  options.forceFixtureReplay && options.fixtureReplay
642
- ? createFixtureTlsClient(options.fixtureReplay.rawText)
643
- : createTlsClient(getProviderBaseUrl(options.provider), {
644
+ ? createFixtureStealthClient(options.fixtureReplay.rawText)
645
+ : createStealthClient(getProviderBaseUrl(options.provider), {
644
646
  apifuseConfig,
645
647
  upstream,
646
648
  });
@@ -657,10 +659,12 @@ function createBaseContext(options: {
657
659
  getScopes: () => [],
658
660
  },
659
661
  http,
660
- tls,
662
+ cache: createBypassProviderCache({ providerId: options.provider.id }),
663
+ stealth,
661
664
  browser: createBrowserStub(),
662
665
  trace: options.traceContext,
663
666
  auth: createAuthStub(),
667
+ stt: createSttClientFromEnv(options.provider.stt),
664
668
  };
665
669
  }
666
670
 
@@ -695,8 +699,8 @@ function createFixtureResponse(raw: unknown) {
695
699
  };
696
700
  }
697
701
 
698
- function createFixtureTlsClient(rawText: string): TlsClient {
699
- const createResponse = async (): Promise<TlsResponse> => ({
702
+ function createFixtureStealthClient(rawText: string): StealthClient {
703
+ const createResponse = async (): Promise<StealthResponse> => ({
700
704
  status: 200,
701
705
  ok: true,
702
706
  headers: { "content-type": "application/json" },
@@ -738,7 +742,7 @@ function buildInsights(
738
742
  ): string[] {
739
743
  const insights: string[] = [];
740
744
  const allSpans = runs.flatMap((run) => run.spans);
741
- const tlsSpans = allSpans.filter((span) => span.name === "tls.fetch");
745
+ const stealthSpans = allSpans.filter((span) => span.name === "stealth.fetch");
742
746
  const dnsSpans = allSpans.filter((span) => span.name === "dns");
743
747
  const transform = breakdown.find(
744
748
  (entry) => entry.name === "transformResponse",
@@ -746,7 +750,7 @@ function buildInsights(
746
750
  const responseSizes = allSpans
747
751
  .map((span) => span.attributes.response_size)
748
752
  .filter((value): value is number => typeof value === "number");
749
- const reuseFlags = tlsSpans
753
+ const reuseFlags = stealthSpans
750
754
  .map((span) => span.attributes.connection_reused)
751
755
  .filter((value): value is boolean => typeof value === "boolean");
752
756
 
@@ -756,8 +760,8 @@ function buildInsights(
756
760
  );
757
761
  insights.push(
758
762
  reusePercent >= 80
759
- ? `✓ TLS connection reuse: ${reusePercent}% (good)`
760
- : `⚠ TLS connection reuse: ${reusePercent}% — consider session reuse`,
763
+ ? `✓ Stealth connection reuse: ${reusePercent}% (good)`
764
+ : `⚠ Stealth connection reuse: ${reusePercent}% — consider session reuse`,
761
765
  );
762
766
  }
763
767
 
@@ -7,13 +7,15 @@ import { basename, dirname, relative, resolve } from "node:path";
7
7
  import { pathToFileURL } from "node:url";
8
8
 
9
9
  import {
10
+ createBypassProviderCache,
10
11
  createHttpClient,
11
- createTlsClient,
12
+ createStealthClient,
13
+ createSttClientFromEnv,
12
14
  executeOperation,
13
15
  type HttpClient,
14
16
  type ProviderContext,
15
17
  type ProviderDefinition,
16
- type TlsClient,
18
+ type StealthClient,
17
19
  } from "../src";
18
20
 
19
21
  type CliArgs = {
@@ -37,6 +39,7 @@ export async function main() {
37
39
  const parsedParams = parseParams(operation, args.params);
38
40
 
39
41
  const capture = createCaptureContext(
42
+ provider,
40
43
  resolveOperationBaseUrl(provider, operationName),
41
44
  );
42
45
 
@@ -269,15 +272,18 @@ function resolveOperationBaseUrl(
269
272
  return baseUrl;
270
273
  }
271
274
 
272
- function createCaptureContext(baseUrl: string) {
275
+ function createCaptureContext(provider: ProviderRuntime, baseUrl: string) {
273
276
  let capturedRaw: unknown;
274
277
 
275
278
  const http = proxyHttpClient(createHttpClient(baseUrl), (response) => {
276
279
  capturedRaw = response.data;
277
280
  });
278
- const tls = proxyTlsClient(createTlsClient(baseUrl), (response) => {
279
- capturedRaw = normalizeCapturedTlsResponse(response);
280
- });
281
+ const stealth = proxyStealthClient(
282
+ createStealthClient(baseUrl),
283
+ (response) => {
284
+ capturedRaw = normalizeCapturedStealthResponse(response);
285
+ },
286
+ );
281
287
 
282
288
  const ctx: ProviderContext = {
283
289
  env: {
@@ -291,7 +297,8 @@ function createCaptureContext(baseUrl: string) {
291
297
  getScopes: () => [],
292
298
  },
293
299
  http,
294
- tls,
300
+ cache: createBypassProviderCache({ providerId: provider.id }),
301
+ stealth,
295
302
  browser: {
296
303
  engine: "playwright-stealth",
297
304
  newPage: async () => {
@@ -306,6 +313,7 @@ function createCaptureContext(baseUrl: string) {
306
313
  throw new Error("Auth prompts are not available in apifuse record.");
307
314
  },
308
315
  },
316
+ stt: createSttClientFromEnv(provider.stt),
309
317
  };
310
318
 
311
319
  return {
@@ -335,59 +343,39 @@ function proxyHttpClient(
335
343
  }) as HttpClient;
336
344
  }
337
345
 
338
- function proxyTlsClient(
339
- client: TlsClient,
340
- onResponse: (response: Awaited<ReturnType<TlsClient["fetch"]>>) => void,
341
- ): TlsClient {
342
- return new Proxy(client, {
343
- get(target, prop, receiver) {
344
- const value = Reflect.get(target, prop, receiver);
345
-
346
- if (prop === "fetch" && typeof value === "function") {
347
- return async (...args: unknown[]) => {
348
- const response = await value.apply(target, args);
349
- onResponse(response);
350
- return response;
351
- };
352
- }
353
-
354
- if (prop === "createSession" && typeof value === "function") {
355
- return (...args: unknown[]) => {
356
- const session = value.apply(target, args) as ReturnType<
357
- TlsClient["createSession"]
358
- >;
359
- return proxyTlsSession(session, onResponse);
360
- };
361
- }
346
+ type StealthSession = ReturnType<StealthClient["createSession"]>;
362
347
 
363
- return value;
348
+ function proxyStealthClient(
349
+ client: StealthClient,
350
+ onResponse: (response: Awaited<ReturnType<StealthClient["fetch"]>>) => void,
351
+ ): StealthClient {
352
+ return {
353
+ fetch: async (...args: Parameters<StealthClient["fetch"]>) => {
354
+ const response = await client.fetch(...args);
355
+ onResponse(response);
356
+ return response;
364
357
  },
365
- }) as TlsClient;
358
+ createSession: (...args: Parameters<StealthClient["createSession"]>) =>
359
+ proxyStealthSession(client.createSession(...args), onResponse),
360
+ };
366
361
  }
367
362
 
368
- function proxyTlsSession(
369
- session: ReturnType<TlsClient["createSession"]>,
370
- onResponse: (response: Awaited<ReturnType<TlsClient["fetch"]>>) => void,
371
- ) {
372
- return new Proxy(session, {
373
- get(target, prop, receiver) {
374
- const value = Reflect.get(target, prop, receiver);
375
-
376
- if (prop === "fetch" && typeof value === "function") {
377
- return async (...args: unknown[]) => {
378
- const response = await value.apply(target, args);
379
- onResponse(response);
380
- return response;
381
- };
382
- }
383
-
384
- return value;
363
+ function proxyStealthSession(
364
+ session: StealthSession,
365
+ onResponse: (response: Awaited<ReturnType<StealthClient["fetch"]>>) => void,
366
+ ): StealthSession {
367
+ return {
368
+ fetch: async (...args: Parameters<StealthSession["fetch"]>) => {
369
+ const response = await session.fetch(...args);
370
+ onResponse(response);
371
+ return response;
385
372
  },
386
- }) as ReturnType<TlsClient["createSession"]>;
373
+ close: () => session.close(),
374
+ };
387
375
  }
388
376
 
389
- function normalizeCapturedTlsResponse(
390
- response: Awaited<ReturnType<TlsClient["fetch"]>>,
377
+ function normalizeCapturedStealthResponse(
378
+ response: Awaited<ReturnType<StealthClient["fetch"]>>,
391
379
  ) {
392
380
  try {
393
381
  return JSON.parse(response.body);
@@ -2,11 +2,19 @@
2
2
 
3
3
  import { existsSync, readFileSync } from "node:fs";
4
4
  import { writeFile } from "node:fs/promises";
5
- import { basename, dirname, resolve } from "node:path";
5
+ import { basename, dirname, join, resolve } from "node:path";
6
6
  import { pathToFileURL } from "node:url";
7
7
 
8
+ import { z } from "zod";
9
+
8
10
  import packageJson from "../package.json";
9
11
  import type { ProviderDefinition } from "../src";
12
+ import {
13
+ loadProviderLocaleCatalogs,
14
+ type ProviderLocale,
15
+ validateProviderLocaleCatalogs,
16
+ } from "../src/i18n";
17
+ import { APIFUSE_DESCRIPTION_KEY_META_KEY } from "../src/schema";
10
18
  import { type CheckResult, runChecks } from "./apifuse-check";
11
19
 
12
20
  const TIERS = ["bronze", "silver", "gold", "diamond"] as const;
@@ -77,6 +85,11 @@ const CATEGORY_MAX_POINTS = {
77
85
  docs: 10,
78
86
  } as const;
79
87
 
88
+ const REQUIRED_PUBLIC_PROVIDER_LOCALES = [
89
+ "en",
90
+ "ko",
91
+ ] as const satisfies readonly ProviderLocale[];
92
+
80
93
  const HELP_TEXT = `Usage: apifuse submit-check [path] [--tier bronze|silver|gold|diamond] [--json] [--markdown <path>] [--smoke-note <text>]
81
94
  Alias: apifuse bounty-check [path]
82
95
  Default: apifuse submit-check .`;
@@ -220,6 +233,7 @@ export async function buildSubmitCheckReport(
220
233
  checks.push(...scoreBaseChecks(baseChecks));
221
234
 
222
235
  if (provider) {
236
+ checks.push(scoreLocaleCatalog(providerRoot, provider));
223
237
  checks.push(scoreOperationMetadata(provider));
224
238
  checks.push(scoreFixtureCoverage(provider));
225
239
  checks.push(scoreHealthCoverage(provider));
@@ -322,12 +336,170 @@ function scoreBaseChecks(results: CheckResult[]): SubmitCheck[] {
322
336
  ];
323
337
  }
324
338
 
339
+ function scoreLocaleCatalog(
340
+ providerRoot: string,
341
+ provider: ProviderDefinition,
342
+ ): SubmitCheck {
343
+ const requiredKeys = collectProviderRequiredLocaleKeys(provider);
344
+ if (requiredKeys.length === 0) {
345
+ return pass(
346
+ "locale-catalog",
347
+ "operations",
348
+ "No key-owned provider metadata or operation metadata requires locale catalog validation.",
349
+ 0,
350
+ );
351
+ }
352
+
353
+ try {
354
+ const availableLocales = REQUIRED_PUBLIC_PROVIDER_LOCALES.filter((locale) =>
355
+ existsSync(join(providerRoot, "locales", `${locale}.json`)),
356
+ );
357
+ const catalogs = loadProviderLocaleCatalogs({
358
+ providerDir: providerRoot,
359
+ locales: availableLocales,
360
+ });
361
+ const validation = validateProviderLocaleCatalogs({
362
+ catalogs,
363
+ requiredLocales: REQUIRED_PUBLIC_PROVIDER_LOCALES,
364
+ requiredKeys,
365
+ });
366
+ if (!validation.ok) {
367
+ return blocker(
368
+ "locale-catalog",
369
+ "operations",
370
+ "Provider locale catalog is missing required public-provider copy.",
371
+ "Add provider-local locales/en.json and locales/ko.json values for every provider metadata key, operation descriptionKey, and .describeKey() or describeKey() schema field.",
372
+ 0,
373
+ validation.issues.map(
374
+ (issue) => `${issue.locale}:${issue.key}: ${issue.message}`,
375
+ ),
376
+ );
377
+ }
378
+ } catch (error) {
379
+ const message = error instanceof Error ? error.message : String(error);
380
+ return blocker(
381
+ "locale-catalog",
382
+ "operations",
383
+ "Provider locale catalog is missing required public-provider copy.",
384
+ "Add provider-local locales/en.json and locales/ko.json values for every provider metadata key, operation descriptionKey, and .describeKey() or describeKey() schema field.",
385
+ 0,
386
+ [`*:*: ${message}`],
387
+ );
388
+ }
389
+
390
+ return pass(
391
+ "locale-catalog",
392
+ "operations",
393
+ "Required provider and operation locale keys resolve in locales/en.json and locales/ko.json.",
394
+ 0,
395
+ );
396
+ }
397
+
398
+ function collectProviderRequiredLocaleKeys(
399
+ provider: ProviderDefinition,
400
+ ): string[] {
401
+ const keys = new Set<string>();
402
+
403
+ addLocaleKeys(keys, [
404
+ provider.meta.descriptionKey,
405
+ provider.meta.docTitleKey,
406
+ provider.meta.docDescriptionKey,
407
+ provider.meta.docSummaryKey,
408
+ provider.meta.docMarkdownKey,
409
+ ]);
410
+
411
+ const publicProfile = provider.meta.publicProfile;
412
+ if (publicProfile) {
413
+ addLocaleKeys(keys, [
414
+ publicProfile.displayNameKey,
415
+ publicProfile.shortDescriptionKey,
416
+ publicProfile.longDescriptionKey,
417
+ publicProfile.setupSummaryKey,
418
+ ...(publicProfile.capabilityKeys ?? []),
419
+ ...(publicProfile.examplePromptKeys ?? []),
420
+ ...(publicProfile.requirementKeys ?? []),
421
+ ...(publicProfile.limitationKeys ?? []),
422
+ ]);
423
+ }
424
+
425
+ for (const operation of Object.values(provider.operations)) {
426
+ addLocaleKeys(keys, [
427
+ operation.descriptionKey,
428
+ operation.docs?.titleKey,
429
+ operation.docs?.descriptionKey,
430
+ operation.docs?.summaryKey,
431
+ operation.docs?.markdownKey,
432
+ ...(operation.whenToUseKeys ?? []),
433
+ ...(operation.whenNotToUseKeys ?? []),
434
+ ...collectSchemaDescriptionKeys(operation.input),
435
+ ...collectSchemaDescriptionKeys(operation.output),
436
+ ]);
437
+ }
438
+
439
+ return Array.from(keys);
440
+ }
441
+
442
+ function addLocaleKeys(keys: Set<string>, values: readonly unknown[]): void {
443
+ for (const key of values) {
444
+ if (typeof key === "string" && key.length > 0) {
445
+ keys.add(key);
446
+ }
447
+ }
448
+ }
449
+
450
+ function collectSchemaDescriptionKeys(schema: unknown): string[] {
451
+ if (!(schema instanceof z.ZodType)) {
452
+ return [];
453
+ }
454
+ const jsonSchema = z.toJSONSchema(schema);
455
+ if (!isRecord(jsonSchema)) {
456
+ return [];
457
+ }
458
+ const keys: string[] = [];
459
+ collectJsonSchemaDescriptionKeys(jsonSchema, keys);
460
+ return keys;
461
+ }
462
+
463
+ function collectJsonSchemaDescriptionKeys(
464
+ schema: Record<string, unknown>,
465
+ keys: string[],
466
+ ): void {
467
+ const descriptionKey = schema[APIFUSE_DESCRIPTION_KEY_META_KEY];
468
+ if (typeof descriptionKey === "string" && descriptionKey.length > 0) {
469
+ keys.push(descriptionKey);
470
+ }
471
+
472
+ for (const value of Object.values(schema)) {
473
+ if (isRecord(value)) {
474
+ collectJsonSchemaDescriptionKeys(value, keys);
475
+ } else if (Array.isArray(value)) {
476
+ for (const item of value) {
477
+ if (isRecord(item)) {
478
+ collectJsonSchemaDescriptionKeys(item, keys);
479
+ }
480
+ }
481
+ }
482
+ }
483
+ }
484
+
485
+ function isRecord(value: unknown): value is Record<string, unknown> {
486
+ return typeof value === "object" && value !== null && !Array.isArray(value);
487
+ }
488
+
325
489
  function scoreOperationMetadata(provider: ProviderDefinition): SubmitCheck {
326
490
  const operations = Object.entries(provider.operations);
327
491
  const weakDescriptions = operations
328
- .filter(
329
- ([, operation]) => (operation.description ?? "").trim().length < 150,
330
- )
492
+ .filter(([, operation]) => {
493
+ // Hard-cut providers move operation copy into locale catalogs via
494
+ // descriptionKey instead of raw inline prose; the resolved text length
495
+ // is enforced at registry catalog-build time, matching how lintOperation
496
+ // skips the raw-description min-length rule when a descriptionKey is set.
497
+ const hasDescriptionKey =
498
+ typeof operation.descriptionKey === "string" &&
499
+ operation.descriptionKey.length > 0;
500
+ if (hasDescriptionKey) return false;
501
+ return true;
502
+ })
331
503
  .map(([operationId]) => operationId);
332
504
  const missingAnnotations = operations
333
505
  .filter(([, operation]) => !operation.annotations)
@@ -520,7 +692,7 @@ function scoreSmokeEvidence(smokeNote: string | undefined): SubmitCheck {
520
692
  maxPoints: CATEGORY_MAX_POINTS.smoke,
521
693
  message: "No local smoke evidence was provided.",
522
694
  remediation:
523
- "Start `bun run dev`, call `/health` and at least one `POST /v1/{operation}`, then rerun with `--smoke-note` or paste notes in the bounty issue.",
695
+ "Start `bun run dev`, call `/health` and at least one `POST /v1/{operation}`, then rerun with `--smoke-note` or paste notes in the assigned workspace PR.",
524
696
  };
525
697
  }
526
698
 
@@ -784,7 +956,7 @@ function blocker(
784
956
 
785
957
  export function renderText(report: SubmitCheckReport): string {
786
958
  const lines = [
787
- `ApiFuse Provider Submission Score: ${report.score.total} / ${report.score.max}`,
959
+ `APIFuse Provider Submission Score: ${report.score.total} / ${report.score.max}`,
788
960
  `Verdict: ${report.score.verdict.toUpperCase()}`,
789
961
  `Provider: ${report.provider.id}@${report.provider.version} (${report.provider.runtime}, auth: ${report.provider.authMode})`,
790
962
  `Blockers: ${report.summary.blockers} Warnings: ${report.summary.warnings} Passed: ${report.summary.passed}`,
@@ -811,7 +983,7 @@ export function renderText(report: SubmitCheckReport): string {
811
983
 
812
984
  export function renderMarkdown(report: SubmitCheckReport): string {
813
985
  const lines = [
814
- "# ApiFuse Provider Submission Report",
986
+ "# APIFuse Provider Submission Report",
815
987
  "",
816
988
  `- **Provider**: ${report.provider.id}@${report.provider.version}`,
817
989
  `- **SDK**: ${report.provider.sdkVersion}`,
package/bin/apifuse.ts CHANGED
@@ -28,7 +28,7 @@ await module.main();
28
28
 
29
29
  function printHelp() {
30
30
  console.log(`
31
- apifuse - ApiFuse Provider SDK CLI
31
+ apifuse - APIFuse Provider SDK CLI
32
32
 
33
33
  Commands:`);
34
34
  for (const name of COMMAND_ORDER) {
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@apifuse/provider-sdk",
3
- "version": "2.1.0-beta.3",
3
+ "version": "2.1.0-beta.4",
4
4
  "private": false,
5
5
  "type": "module",
6
- "description": "ApiFuse Provider SDK — Build providers with zero architectural constraints",
6
+ "description": "APIFuse Provider SDK — Build providers with zero architectural constraints",
7
7
  "license": "MIT",
8
8
  "main": "./src/index.ts",
9
9
  "types": "./src/index.ts",
@@ -53,6 +53,11 @@
53
53
  "default": "./src/testing/index.ts",
54
54
  "import": "./src/testing/index.ts",
55
55
  "types": "./src/testing/index.ts"
56
+ },
57
+ "./create": {
58
+ "default": "./src/cli/create.ts",
59
+ "import": "./src/cli/create.ts",
60
+ "types": "./src/cli/create.ts"
56
61
  }
57
62
  },
58
63
  "scripts": {
@@ -66,20 +71,24 @@
66
71
  "pack:smoke": "bun bin/apifuse-pack-smoke.ts"
67
72
  },
68
73
  "devDependencies": {
69
- "@biomejs/biome": "^2.4.15",
74
+ "@biomejs/biome": "^2.5.0",
70
75
  "@types/bun": "latest",
71
- "@types/node": "^25.8.0",
76
+ "@types/node": "^25.9.3",
72
77
  "typescript": "^6.0.3"
73
78
  },
74
79
  "dependencies": {
75
- "@clack/prompts": "^1.4.0",
80
+ "@clack/prompts": "^1.5.1",
81
+ "@types/ms": "^2.1.0",
76
82
  "ajv": "^8.17",
77
- "hono": "^4.12.19",
83
+ "hono": "^4.12.25",
84
+ "impit": "0.14.1",
85
+ "ioredis": "^5.11.1",
86
+ "ms": "^2.1.3",
78
87
  "playwright": "^1.55.1",
79
- "playwright-stealth": "^0.0.1",
88
+ "playwright-extra": "^4.3.6",
89
+ "puppeteer-extra-plugin-stealth": "^2.11.2",
80
90
  "re2-wasm": "^1.0",
81
91
  "safe-regex": "^2.1",
82
- "tlsclientwrapper": "^4.2.0",
83
92
  "zod": "^4.4.3"
84
93
  }
85
94
  }