@apifuse/provider-sdk 2.2.0-beta.3 → 2.2.0-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. package/AUTHORING.md +14 -0
  2. package/CHANGELOG.md +4 -0
  3. package/bin/apifuse-check.ts +18 -58
  4. package/bin/apifuse-create.ts +1 -1
  5. package/bin/apifuse-dev.ts +27 -52
  6. package/bin/apifuse-pack-smoke.ts +22 -81
  7. package/bin/apifuse-pack-types.ts +266 -0
  8. package/bin/apifuse-perf.ts +45 -127
  9. package/bin/apifuse-record.ts +23 -61
  10. package/bin/apifuse-submit-check.ts +26 -21
  11. package/bin/apifuse.ts +1 -1
  12. package/bin/submit-check-xml.ts +1 -1
  13. package/dist/auth-turn/index.d.ts +1 -1
  14. package/dist/auth.d.ts +2 -2
  15. package/dist/auth.js +9 -18
  16. package/dist/ceremonies/index.d.ts +1 -1
  17. package/dist/ceremonies/index.js +8 -18
  18. package/dist/config/loader.d.ts +2 -2
  19. package/dist/config/loader.js +19 -42
  20. package/dist/contract-serialization.d.ts +2 -2
  21. package/dist/contract-serialization.js +3 -6
  22. package/dist/contract-types.d.ts +2 -2
  23. package/dist/contract.d.ts +3 -3
  24. package/dist/contract.js +4 -6
  25. package/dist/define.d.ts +8 -1
  26. package/dist/define.js +57 -115
  27. package/dist/dev.d.ts +1 -1
  28. package/dist/dev.js +1 -1
  29. package/dist/errors.d.ts +1 -1
  30. package/dist/errors.js +1 -3
  31. package/dist/i18n/catalog.d.ts +2 -2
  32. package/dist/i18n/catalog.js +4 -10
  33. package/dist/i18n/index.d.ts +2 -2
  34. package/dist/i18n/index.js +2 -2
  35. package/dist/i18n/keys.d.ts +2 -2
  36. package/dist/index.d.ts +43 -42
  37. package/dist/index.js +38 -37
  38. package/dist/lint.js +8 -15
  39. package/dist/provider.d.ts +11 -11
  40. package/dist/provider.js +9 -9
  41. package/dist/public-schema-field-lint.d.ts +1 -1
  42. package/dist/recipes/gov-api.js +1 -1
  43. package/dist/runtime/auth-flow.d.ts +1 -1
  44. package/dist/runtime/auth-flow.js +3 -3
  45. package/dist/runtime/browser.d.ts +1 -1
  46. package/dist/runtime/browser.js +15 -29
  47. package/dist/runtime/cache.d.ts +1 -1
  48. package/dist/runtime/cache.js +4 -8
  49. package/dist/runtime/choice.d.ts +1 -1
  50. package/dist/runtime/choice.js +12 -34
  51. package/dist/runtime/credential.d.ts +1 -1
  52. package/dist/runtime/credential.js +1 -1
  53. package/dist/runtime/env.d.ts +1 -1
  54. package/dist/runtime/executor.d.ts +1 -1
  55. package/dist/runtime/executor.js +2 -2
  56. package/dist/runtime/http.d.ts +2 -2
  57. package/dist/runtime/http.js +5 -5
  58. package/dist/runtime/insights.d.ts +1 -1
  59. package/dist/runtime/insights.js +6 -13
  60. package/dist/runtime/instrumentation.d.ts +2 -2
  61. package/dist/runtime/instrumentation.js +5 -15
  62. package/dist/runtime/keyring.js +1 -1
  63. package/dist/runtime/namespace.js +1 -1
  64. package/dist/runtime/otlp.d.ts +1 -1
  65. package/dist/runtime/perf.d.ts +1 -1
  66. package/dist/runtime/provider.d.ts +1 -1
  67. package/dist/runtime/provider.js +1 -2
  68. package/dist/runtime/proxy-errors.d.ts +1 -1
  69. package/dist/runtime/proxy-errors.js +3 -5
  70. package/dist/runtime/proxy-retry-policy.d.ts +2 -2
  71. package/dist/runtime/proxy-retry-policy.js +2 -2
  72. package/dist/runtime/proxy-telemetry.d.ts +1 -1
  73. package/dist/runtime/proxy-telemetry.js +16 -48
  74. package/dist/runtime/redis.d.ts +1 -1
  75. package/dist/runtime/redis.js +2 -4
  76. package/dist/runtime/request-options.d.ts +1 -1
  77. package/dist/runtime/state.d.ts +2 -2
  78. package/dist/runtime/state.js +3 -3
  79. package/dist/runtime/stealth.d.ts +2 -2
  80. package/dist/runtime/stealth.js +6 -6
  81. package/dist/runtime/stt.d.ts +1 -1
  82. package/dist/runtime/stt.js +11 -15
  83. package/dist/runtime/trace.d.ts +2 -2
  84. package/dist/runtime/trace.js +2 -4
  85. package/dist/runtime/waterfall.d.ts +1 -1
  86. package/dist/schema.d.ts +1 -1
  87. package/dist/schema.js +7 -15
  88. package/dist/serve.d.ts +1 -1
  89. package/dist/serve.js +1 -1
  90. package/dist/server/index.d.ts +7 -7
  91. package/dist/server/index.js +6 -6
  92. package/dist/server/self-test-redaction.d.ts +1 -1
  93. package/dist/server/self-test-redaction.js +1 -1
  94. package/dist/server/self-test.d.ts +3 -3
  95. package/dist/server/self-test.js +3 -3
  96. package/dist/server/serve.d.ts +3 -3
  97. package/dist/server/serve.js +36 -49
  98. package/dist/server/types.js +2 -7
  99. package/dist/stealth/profiles.d.ts +1 -1
  100. package/dist/stealth/profiles.js +5 -14
  101. package/dist/stream.d.ts +1 -1
  102. package/dist/testing/index.d.ts +2 -2
  103. package/dist/testing/index.js +2 -2
  104. package/dist/testing/run.d.ts +1 -1
  105. package/dist/testing/run.js +7 -14
  106. package/dist/types.d.ts +57 -0
  107. package/dist/user-input.d.ts +30 -0
  108. package/dist/user-input.js +66 -0
  109. package/package.json +6 -4
  110. package/src/auth-turn/index.ts +1 -1
  111. package/src/auth.ts +28 -86
  112. package/src/ceremonies/index.ts +24 -78
  113. package/src/config/loader.ts +58 -176
  114. package/src/contract-serialization.ts +5 -11
  115. package/src/contract-types.ts +2 -2
  116. package/src/contract.ts +12 -28
  117. package/src/define.ts +174 -495
  118. package/src/dev.ts +4 -9
  119. package/src/errors.ts +4 -11
  120. package/src/i18n/catalog.ts +10 -32
  121. package/src/i18n/index.ts +2 -2
  122. package/src/i18n/keys.ts +5 -11
  123. package/src/index.ts +44 -42
  124. package/src/lint.ts +89 -159
  125. package/src/provider.ts +12 -11
  126. package/src/public-schema-field-lint.ts +7 -33
  127. package/src/recipes/gov-api.ts +2 -5
  128. package/src/runtime/auth-flow.ts +5 -7
  129. package/src/runtime/browser.ts +64 -187
  130. package/src/runtime/cache.ts +20 -67
  131. package/src/runtime/choice.ts +55 -129
  132. package/src/runtime/credential.ts +2 -2
  133. package/src/runtime/env.ts +1 -1
  134. package/src/runtime/executor.ts +9 -19
  135. package/src/runtime/http.ts +7 -7
  136. package/src/runtime/insights.ts +15 -53
  137. package/src/runtime/instrumentation.ts +19 -58
  138. package/src/runtime/keyring.ts +7 -19
  139. package/src/runtime/namespace.ts +2 -7
  140. package/src/runtime/otlp.ts +12 -23
  141. package/src/runtime/perf.ts +1 -1
  142. package/src/runtime/provider.ts +4 -9
  143. package/src/runtime/proxy-errors.ts +17 -38
  144. package/src/runtime/proxy-retry-policy.ts +3 -3
  145. package/src/runtime/proxy-telemetry.ts +23 -72
  146. package/src/runtime/redis.ts +4 -12
  147. package/src/runtime/request-options.ts +4 -13
  148. package/src/runtime/state.ts +30 -109
  149. package/src/runtime/stealth.ts +8 -8
  150. package/src/runtime/stt.ts +38 -94
  151. package/src/runtime/trace.ts +14 -44
  152. package/src/runtime/waterfall.ts +5 -18
  153. package/src/schema.ts +23 -84
  154. package/src/serve.ts +1 -1
  155. package/src/server/index.ts +7 -7
  156. package/src/server/self-test-redaction.ts +2 -2
  157. package/src/server/self-test.ts +5 -5
  158. package/src/server/serve.ts +87 -242
  159. package/src/server/types.ts +6 -19
  160. package/src/stealth/profiles.ts +10 -26
  161. package/src/stream.ts +8 -19
  162. package/src/testing/index.ts +2 -2
  163. package/src/testing/run.ts +19 -67
  164. package/src/types.ts +58 -0
  165. package/src/user-input.ts +118 -0
@@ -20,8 +20,8 @@ import {
20
20
  type StealthClient,
21
21
  TransportError,
22
22
  ValidationError,
23
- } from "../src";
24
- import { createMemoryProviderRuntimeState } from "../src/runtime/state";
23
+ } from "../src/index.js";
24
+ import { createMemoryProviderRuntimeState } from "../src/runtime/state.js";
25
25
 
26
26
  type CliArgs = {
27
27
  append: boolean;
@@ -64,31 +64,18 @@ export async function main() {
64
64
  resolveOperationBaseUrl(provider, operationName),
65
65
  );
66
66
 
67
- console.log(
68
- `[apifuse record] Calling ${operationName} on ${provider.id}...`,
69
- );
67
+ console.log(`[apifuse record] Calling ${operationName} on ${provider.id}...`);
70
68
 
71
- const result = await executeOperation(
72
- provider,
73
- operationName,
74
- capture.ctx,
75
- parsedParams,
76
- );
69
+ const result = await executeOperation(provider, operationName, capture.ctx, parsedParams);
77
70
  const captured = capture.getCapturedRaw();
78
71
 
79
72
  if (captured === undefined) {
80
- throw new Error(
81
- `No upstream response was captured for ${provider.id}.${operationName}.`,
82
- );
73
+ throw new Error(`No upstream response was captured for ${provider.id}.${operationName}.`);
83
74
  }
84
75
 
85
76
  const rawPayload = args.sanitize ? sanitizeFixture(captured) : captured;
86
77
  const fixturePath = resolve(location.rootDir, "__fixtures__", "raw.json");
87
- const nextPayload = await prepareFixturePayload(
88
- fixturePath,
89
- rawPayload,
90
- args.append,
91
- );
78
+ const nextPayload = await prepareFixturePayload(fixturePath, rawPayload, args.append);
92
79
 
93
80
  await mkdir(dirname(fixturePath), { recursive: true });
94
81
  await writeFile(fixturePath, `${JSON.stringify(nextPayload, null, 2)}\n`);
@@ -98,9 +85,7 @@ export async function main() {
98
85
  Buffer.byteLength(JSON.stringify(rawPayload)),
99
86
  )})`,
100
87
  );
101
- console.log(
102
- `[apifuse record] Saved to ${relative(process.cwd(), fixturePath)}`,
103
- );
88
+ console.log(`[apifuse record] Saved to ${relative(process.cwd(), fixturePath)}`);
104
89
 
105
90
  void result;
106
91
  } catch (error) {
@@ -210,11 +195,7 @@ function formatCliError(error: unknown): string {
210
195
  }
211
196
 
212
197
  if (error instanceof ProviderError || error instanceof ValidationError) {
213
- return [
214
- error.message,
215
- error.code ? `code=${error.code}` : undefined,
216
- error.fix,
217
- ]
198
+ return [error.message, error.code ? `code=${error.code}` : undefined, error.fix]
218
199
  .filter(Boolean)
219
200
  .join(" ");
220
201
  }
@@ -269,8 +250,7 @@ function findProviderRoot(startDirectory: string): string | undefined {
269
250
 
270
251
  function looksLikeProviderRoot(directory: string): boolean {
271
252
  return (
272
- existsSync(resolve(directory, "index.ts")) &&
273
- existsSync(resolve(directory, "package.json"))
253
+ existsSync(resolve(directory, "index.ts")) && existsSync(resolve(directory, "package.json"))
274
254
  );
275
255
  }
276
256
 
@@ -287,15 +267,10 @@ async function loadProvider(rootDir: string): Promise<ProviderRuntime> {
287
267
  return module.default;
288
268
  }
289
269
 
290
- function resolveOperationName(
291
- provider: ProviderRuntime,
292
- operationName?: string,
293
- ): string {
270
+ function resolveOperationName(provider: ProviderRuntime, operationName?: string): string {
294
271
  if (operationName) {
295
272
  if (!(operationName in provider.operations)) {
296
- throw new Error(
297
- `Unknown operation "${operationName}" for provider "${provider.id}".`,
298
- );
273
+ throw new Error(`Unknown operation "${operationName}" for provider "${provider.id}".`);
299
274
  }
300
275
 
301
276
  return operationName;
@@ -309,10 +284,7 @@ function resolveOperationName(
309
284
  return firstOperation;
310
285
  }
311
286
 
312
- function parseParams(
313
- operation: ProviderRuntime["operations"][string],
314
- value: string,
315
- ): unknown {
287
+ function parseParams(operation: ProviderRuntime["operations"][string], value: string): unknown {
316
288
  let parsed: unknown;
317
289
 
318
290
  try {
@@ -326,10 +298,7 @@ function parseParams(
326
298
  return operation.input ? operation.input.parse(parsed) : parsed;
327
299
  }
328
300
 
329
- function resolveOperationBaseUrl(
330
- provider: ProviderRuntime,
331
- operationName: string,
332
- ): string {
301
+ function resolveOperationBaseUrl(provider: ProviderRuntime, operationName: string): string {
333
302
  const baseUrl = provider.operations[operationName]?.upstream?.baseUrl;
334
303
  if (!baseUrl) {
335
304
  throw new Error(
@@ -346,12 +315,9 @@ function createCaptureContext(provider: ProviderRuntime, baseUrl: string) {
346
315
  const http = proxyHttpClient(createHttpClient(baseUrl), (response) => {
347
316
  capturedRaw = response.data;
348
317
  });
349
- const stealth = proxyStealthClient(
350
- createStealthClient(baseUrl),
351
- (response) => {
352
- capturedRaw = normalizeCapturedStealthResponse(response);
353
- },
354
- );
318
+ const stealth = proxyStealthClient(createStealthClient(baseUrl), (response) => {
319
+ capturedRaw = normalizeCapturedStealthResponse(response);
320
+ });
355
321
 
356
322
  const env = {
357
323
  get: (key: string) => process.env[key],
@@ -464,9 +430,7 @@ function proxyStealthSession(
464
430
  };
465
431
  }
466
432
 
467
- function normalizeCapturedStealthResponse(
468
- response: Awaited<ReturnType<StealthClient["fetch"]>>,
469
- ) {
433
+ function normalizeCapturedStealthResponse(response: Awaited<ReturnType<StealthClient["fetch"]>>) {
470
434
  try {
471
435
  return JSON.parse(response.body);
472
436
  } catch {
@@ -483,15 +447,13 @@ function sanitizeFixture(value: unknown): unknown {
483
447
  return value;
484
448
  }
485
449
 
486
- const entries = Object.entries(value as MutableRecord).map(
487
- ([key, entryValue]) => {
488
- if (isSensitiveKey(key)) {
489
- return [key, "[REDACTED]"] as const;
490
- }
450
+ const entries = Object.entries(value as MutableRecord).map(([key, entryValue]) => {
451
+ if (isSensitiveKey(key)) {
452
+ return [key, "[REDACTED]"] as const;
453
+ }
491
454
 
492
- return [key, sanitizeFixture(entryValue)] as const;
493
- },
494
- );
455
+ return [key, sanitizeFixture(entryValue)] as const;
456
+ });
495
457
 
496
458
  return Object.fromEntries(entries);
497
459
  }
@@ -11,16 +11,16 @@ import * as acorn from "acorn";
11
11
  import { z } from "zod";
12
12
 
13
13
  import packageJson from "../package.json";
14
- import type { ProviderDefinition } from "../src";
14
+ import type { ProviderDefinition } from "../src/index.js";
15
15
  import {
16
16
  loadProviderLocaleCatalogs,
17
17
  type ProviderLocale,
18
18
  validateProviderLocaleCatalogs,
19
- } from "../src/i18n";
20
- import { APIFUSE_DESCRIPTION_KEY_META_KEY } from "../src/schema";
21
- import { safeParseSchemaSync } from "../src/schema";
22
- import { type CheckResult, runChecks } from "./apifuse-check";
23
- import { hasSubstantiveXmlStructure } from "./submit-check-xml";
19
+ } from "../src/i18n/index.js";
20
+ import { APIFUSE_DESCRIPTION_KEY_META_KEY } from "../src/schema.js";
21
+ import { safeParseSchemaSync } from "../src/schema.js";
22
+ import { type CheckResult, runChecks } from "./apifuse-check.js";
23
+ import { hasSubstantiveXmlStructure } from "./submit-check-xml.js";
24
24
 
25
25
  const TIERS = ["bronze", "silver", "gold", "diamond"] as const;
26
26
  const TIER_VALUES: ReadonlySet<string> = new Set(TIERS);
@@ -1980,10 +1980,7 @@ function scoreFixtureCoverage(provider: ProviderDefinition): SubmitCheck {
1980
1980
 
1981
1981
  const GENERATED_LOCAL_ONLY_SCAFFOLD_REASON = /generated local-only scaffold/i;
1982
1982
 
1983
- function scoreFixtureProvenance(
1984
- providerRoot: string,
1985
- provider: ProviderDefinition,
1986
- ): SubmitCheck {
1983
+ function scoreFixtureProvenance(providerRoot: string, provider: ProviderDefinition): SubmitCheck {
1987
1984
  const rawPath = resolve(providerRoot, "__fixtures__", "raw.json");
1988
1985
  let hasRecordedEvidence = false;
1989
1986
  if (existsSync(rawPath)) {
@@ -2090,12 +2087,17 @@ function allOperationsAreGeneratedLocalScaffold(provider: ProviderDefinition): b
2090
2087
  }
2091
2088
 
2092
2089
  function scoreVendorKeyLeak(providerRoot: string): SubmitCheck {
2093
- return escapeHatchResult(providerRoot, "vendor-key-leak", findVendorKeyLeakFindings(providerRoot), {
2094
- blockerMessage: "Public schema keys leak raw vendor field names.",
2095
- remediation:
2096
- "Normalize public request/response fields to APIFuse-standard lowerCamelCase names (e.g. isOpen24h, latitude); keep raw vendor keys only in upstream-parsing schemas (const upstream... = z.object(...)). Add `// @apifuse-allow vendor-key-leak` only with a comment explaining why the vendor name is genuinely canonical.",
2097
- passMessage: "No vendor field-name leaks detected in public schemas.",
2098
- });
2090
+ return escapeHatchResult(
2091
+ providerRoot,
2092
+ "vendor-key-leak",
2093
+ findVendorKeyLeakFindings(providerRoot),
2094
+ {
2095
+ blockerMessage: "Public schema keys leak raw vendor field names.",
2096
+ remediation:
2097
+ "Normalize public request/response fields to APIFuse-standard lowerCamelCase names (e.g. isOpen24h, latitude); keep raw vendor keys only in upstream-parsing schemas (const upstream... = z.object(...)). Add `// @apifuse-allow vendor-key-leak` only with a comment explaining why the vendor name is genuinely canonical.",
2098
+ passMessage: "No vendor field-name leaks detected in public schemas.",
2099
+ },
2100
+ );
2099
2101
  }
2100
2102
 
2101
2103
  function scoreVendorTimestampLeak(providerRoot: string): SubmitCheck {
@@ -2282,9 +2284,7 @@ function collectTopLevelObjectKeys(
2282
2284
  if (computedQuote === '"' || computedQuote === "'") {
2283
2285
  const literalEnd = findStringEnd(source, literalStart);
2284
2286
  const afterLiteral =
2285
- literalEnd === -1
2286
- ? -1
2287
- : skipWhitespaceAndComments(masked, literalEnd + 1, computedEnd);
2287
+ literalEnd === -1 ? -1 : skipWhitespaceAndComments(masked, literalEnd + 1, computedEnd);
2288
2288
  if (literalEnd !== -1 && afterLiteral === computedEnd) {
2289
2289
  key = source.slice(literalStart + 1, literalEnd);
2290
2290
  }
@@ -2402,8 +2402,13 @@ function findNamedConstValueRanges(source: string): NamedObjectRange[] {
2402
2402
  return ranges;
2403
2403
  }
2404
2404
 
2405
- function findConstValueRangeContaining(source: string, offset: number): NamedObjectRange | undefined {
2406
- return findNamedConstValueRanges(source).find((range) => offset >= range.start && offset <= range.end);
2405
+ function findConstValueRangeContaining(
2406
+ source: string,
2407
+ offset: number,
2408
+ ): NamedObjectRange | undefined {
2409
+ return findNamedConstValueRanges(source).find(
2410
+ (range) => offset >= range.start && offset <= range.end,
2411
+ );
2407
2412
  }
2408
2413
 
2409
2414
  function findStringLiteralsInRange(
package/bin/apifuse.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env bun
2
2
 
3
3
  import packageJson from "../package.json";
4
- import { COMMAND_MANIFEST, COMMAND_ORDER } from "../src/cli/commands";
4
+ import { COMMAND_MANIFEST, COMMAND_ORDER } from "../src/cli/commands.js";
5
5
 
6
6
  const command = process.argv[2];
7
7
 
@@ -14,7 +14,7 @@ import {
14
14
  normalizedXmlName,
15
15
  rootXmlContext,
16
16
  type XmlSemanticBranch,
17
- } from "./submit-check-xml-semantics";
17
+ } from "./submit-check-xml-semantics.js";
18
18
 
19
19
  const MIN_RECORDED_XML_LENGTH = 128;
20
20
  // Recorded fixtures must remain reviewable; this pre-allocation cap also bounds the parser tree.
@@ -1,4 +1,4 @@
1
- import type { AuthTurn } from "../types";
1
+ import type { AuthTurn } from "../types.js";
2
2
  export type { AuthTurn };
3
3
  /**
4
4
  * Major version of the AuthTurn envelope contract.
package/dist/auth.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { AuthError } from "./errors";
2
- import type { AuthConfig, AuthFlowTerminalContext, AuthTurn, ContextDeclaration, CredentialDeclaration, FlowContext, ProviderLocaleKeyInput } from "./types";
1
+ import { AuthError } from "./errors.js";
2
+ import type { AuthConfig, AuthFlowTerminalContext, AuthTurn, ContextDeclaration, CredentialDeclaration, FlowContext, ProviderLocaleKeyInput } from "./types.js";
3
3
  export type CredentialsAuthFieldType = "string" | "email" | "password" | "otp";
4
4
  export interface CredentialsAuthField {
5
5
  type?: CredentialsAuthFieldType;
package/dist/auth.js CHANGED
@@ -1,4 +1,4 @@
1
- import { AuthError, ProviderError } from "./errors";
1
+ import { AuthError, ProviderError } from "./errors.js";
2
2
  const CREDENTIALS_AUTH_CHALLENGE_CONTEXT_KEY = "__credentialsAuthChallenge";
3
3
  const DEFAULT_COMPLETE_TURN_ID = "auth.complete";
4
4
  const DEFAULT_ABORT_TURN_ID = "auth.abort";
@@ -97,7 +97,7 @@ export function createAuthFlowHelpers(options = {}) {
97
97
  },
98
98
  };
99
99
  },
100
- abort({ code, message, retry, actionHint, fieldErrors, data, turnId, expiresAt, }) {
100
+ abort({ code, message, retry, actionHint, fieldErrors, data, turnId, expiresAt }) {
101
101
  return {
102
102
  kind: "abort",
103
103
  ...authTurnBase({ turnId, defaultTurnId: DEFAULT_ABORT_TURN_ID, expiresAt }),
@@ -169,12 +169,8 @@ function expectedInputFromFields(fields) {
169
169
  ...(field.type === "password" ? { format: "password" } : {}),
170
170
  ...(field.type === "otp" ? { format: "otp" } : {}),
171
171
  ...(field.labelKey ? { nameKey: field.labelKey } : {}),
172
- ...(field.descriptionKey
173
- ? { descriptionKey: field.descriptionKey }
174
- : {}),
175
- ...(field.placeholderKey
176
- ? { placeholderKey: field.placeholderKey }
177
- : {}),
172
+ ...(field.descriptionKey ? { descriptionKey: field.descriptionKey } : {}),
173
+ ...(field.placeholderKey ? { placeholderKey: field.placeholderKey } : {}),
178
174
  ...(field.sensitive || field.type === "password" || field.type === "otp"
179
175
  ? { sensitive: true }
180
176
  : {}),
@@ -291,17 +287,15 @@ function completeTurn(credentialKeys, result, defaultTurnId) {
291
287
  };
292
288
  }
293
289
  function challengeTurn(definition, request) {
294
- const expectedInput = definition.fields
295
- ? expectedInputFromFields(definition.fields)
296
- : undefined;
290
+ const expectedInput = definition.fields ? expectedInputFromFields(definition.fields) : undefined;
297
291
  return {
298
292
  kind: expectedInput ? "form" : "pending",
299
293
  turnId: request.turnId ?? definition.turnId ?? `credentials.${request.challengeId}`,
300
294
  ...(request.expiresAt ? { expiresAt: request.expiresAt } : {}),
301
- ...(request.hintKey ?? definition.hintKey
295
+ ...((request.hintKey ?? definition.hintKey)
302
296
  ? { hintKey: request.hintKey ?? definition.hintKey }
303
297
  : {}),
304
- ...(request.timing ?? definition.timing
298
+ ...((request.timing ?? definition.timing)
305
299
  ? { timing: request.timing ?? definition.timing }
306
300
  : {}),
307
301
  ...(expectedInput ? { expectedInput } : {}),
@@ -378,7 +372,7 @@ async function pollPendingChallenge(ctx, credentialKeys, challenges, pending, co
378
372
  export function defineCredentialsAuth(options) {
379
373
  if (Object.keys(options.fields).length === 0) {
380
374
  throw new ProviderError("defineCredentialsAuth requires at least one field", {
381
- fix: "Pass fields such as { email: { type: \"email\" }, password: { type: \"password\" } }.",
375
+ fix: 'Pass fields such as { email: { type: "email" }, password: { type: "password" } }.',
382
376
  });
383
377
  }
384
378
  const expectedInput = expectedInputFromFields(options.fields);
@@ -427,10 +421,7 @@ export function defineCredentialsAuth(options) {
427
421
  ...(options.justification ? { justification: options.justification } : {}),
428
422
  },
429
423
  context: {
430
- keys: Array.from(new Set([
431
- CREDENTIALS_AUTH_CHALLENGE_CONTEXT_KEY,
432
- ...(options.contextKeys ?? []),
433
- ])),
424
+ keys: Array.from(new Set([CREDENTIALS_AUTH_CHALLENGE_CONTEXT_KEY, ...(options.contextKeys ?? [])])),
434
425
  },
435
426
  };
436
427
  }
@@ -1,4 +1,4 @@
1
- import type { AuthFlowDefinition, AuthTurn } from "../types";
1
+ import type { AuthFlowDefinition, AuthTurn } from "../types.js";
2
2
  type JsonObject = Record<string, unknown>;
3
3
  export declare function validateCeremonyOutput(turn: unknown): AuthTurn;
4
4
  export declare function createOAuth2Ceremony(options: {
@@ -1,7 +1,7 @@
1
1
  import { createHash, randomBytes, randomUUID } from "node:crypto";
2
2
  import Ajv2020 from "ajv/dist/2020.js";
3
- import { AUTH_TURN_SCHEMA } from "../auth-turn";
4
- import { FlowExpiredError, ProviderSecretError, TurnValidationError, ValidationError, } from "../errors";
3
+ import { AUTH_TURN_SCHEMA } from "../auth-turn/index.js";
4
+ import { FlowExpiredError, ProviderSecretError, TurnValidationError, ValidationError, } from "../errors.js";
5
5
  const ajv = new Ajv2020({ allErrors: true, strict: true, strictSchema: true });
6
6
  // Runtime ceremony-output validation derives from the exported versioned
7
7
  // contract: it compiles the exact AUTH_TURN_SCHEMA document shipped at
@@ -38,11 +38,7 @@ function getRequiredEnv(ctx, key) {
38
38
  return value;
39
39
  }
40
40
  function toBase64Url(input) {
41
- return input
42
- .toString("base64")
43
- .replace(/\+/g, "-")
44
- .replace(/\//g, "_")
45
- .replace(/=+$/g, "");
41
+ return input.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
46
42
  }
47
43
  function createCodeVerifier() {
48
44
  return toBase64Url(randomBytes(32));
@@ -100,8 +96,7 @@ function withDeclaredFormFieldOrder(expectedInput) {
100
96
  return expectedInput;
101
97
  }
102
98
  const existingOrder = expectedInput[FORM_FIELD_ORDER_EXTENSION];
103
- if (Array.isArray(existingOrder) &&
104
- existingOrder.every((value) => typeof value === "string")) {
99
+ if (Array.isArray(existingOrder) && existingOrder.every((value) => typeof value === "string")) {
105
100
  return expectedInput;
106
101
  }
107
102
  return {
@@ -218,8 +213,7 @@ export function createDeviceFlowCeremony(options) {
218
213
  });
219
214
  const data = ensureRecord(response.data);
220
215
  const errorCode = getString(data, "error");
221
- if (errorCode === "authorization_pending" ||
222
- errorCode === "slow_down") {
216
+ if (errorCode === "authorization_pending" || errorCode === "slow_down") {
223
217
  return createTurn("poll", {
224
218
  data,
225
219
  hint: "Authorization pending.",
@@ -345,7 +339,7 @@ export function createFormCeremony(options) {
345
339
  return {
346
340
  start: async () => validateCeremonyOutput(buildJsonSchemaForm(options.schema, options.hint ?? "Provide the required input to continue.")),
347
341
  continue: (ctx, input = {}) => runCeremonyHandler(async () => {
348
- const { prevalidate } = await import("../runtime/prevalidate");
342
+ const { prevalidate } = await import("../runtime/prevalidate.js");
349
343
  const result = prevalidate(options.schema, input);
350
344
  if (!result.valid) {
351
345
  throw new ValidationError("Form input failed validation.", {
@@ -354,9 +348,7 @@ export function createFormCeremony(options) {
354
348
  }
355
349
  return createTurn("complete", {
356
350
  data: {
357
- credential: options.mapCredential
358
- ? options.mapCredential(input)
359
- : input,
351
+ credential: options.mapCredential ? options.mapCredential(input) : input,
360
352
  },
361
353
  hint: "Form completed.",
362
354
  });
@@ -428,9 +420,7 @@ export function createSwitchCeremony(options) {
428
420
  })),
429
421
  continue: (ctx, input = {}) => runCeremonyHandler(async () => {
430
422
  const storedChoice = ctx.context.get(SWITCH_SELECTION_KEY);
431
- const choice = typeof storedChoice === "string"
432
- ? storedChoice
433
- : getString(input, "choice");
423
+ const choice = typeof storedChoice === "string" ? storedChoice : getString(input, "choice");
434
424
  if (!choice || !options.choices[choice]) {
435
425
  throw new ValidationError("A valid choice is required.");
436
426
  }
@@ -1,5 +1,5 @@
1
- import Redis from "ioredis";
2
- import type { ProviderProxyPolicy, TraceConfig } from "../types";
1
+ import { Redis } from "ioredis";
2
+ import type { ProviderProxyPolicy, TraceConfig } from "../types.js";
3
3
  export declare const SMARTPROXY_APP_KEY_ENV = "APIFUSE__PROXY__SMARTPROXY_APP_KEY";
4
4
  export declare const SMARTPROXY_MAX_LIFETIME_MINUTES = 2000;
5
5
  export declare const DEFAULT_SMARTPROXY_POOL_SIZE = 20;
@@ -1,7 +1,7 @@
1
1
  import { createHash, randomUUID } from "node:crypto";
2
2
  import { existsSync } from "node:fs";
3
3
  import path from "node:path";
4
- import Redis from "ioredis";
4
+ import { Redis } from "ioredis";
5
5
  export const SMARTPROXY_APP_KEY_ENV = "APIFUSE__PROXY__SMARTPROXY_APP_KEY";
6
6
  export const SMARTPROXY_MAX_LIFETIME_MINUTES = 2000;
7
7
  export const DEFAULT_SMARTPROXY_POOL_SIZE = 20;
@@ -160,9 +160,7 @@ function toProxyDiagnostics(value) {
160
160
  return undefined;
161
161
  const diagnostics = {};
162
162
  for (const [key, item] of Object.entries(value)) {
163
- if (typeof item === "string" ||
164
- typeof item === "number" ||
165
- typeof item === "boolean") {
163
+ if (typeof item === "string" || typeof item === "number" || typeof item === "boolean") {
166
164
  diagnostics[key] = item;
167
165
  }
168
166
  }
@@ -249,9 +247,7 @@ function applyStickyProxySession(proxyUrl) {
249
247
  }
250
248
  function buildSmartproxyUsername(username, sessionId, sessionDuration) {
251
249
  const parts = username.split("_");
252
- const configuredLife = parts
253
- .find((part) => part.startsWith("life-"))
254
- ?.slice("life-".length);
250
+ const configuredLife = parts.find((part) => part.startsWith("life-"))?.slice("life-".length);
255
251
  const baseUsername = parts
256
252
  .filter((part) => !part.startsWith("session-") && !part.startsWith("life-"))
257
253
  .join("_");
@@ -259,9 +255,7 @@ function buildSmartproxyUsername(username, sessionId, sessionDuration) {
259
255
  }
260
256
  function buildDecodoUsername(username, sessionId, sessionDuration) {
261
257
  const withoutSticky = username.replace(/-session-.+-sessionduration-\d+$/, "");
262
- const baseUsername = withoutSticky.startsWith("user-")
263
- ? withoutSticky
264
- : `user-${withoutSticky}`;
258
+ const baseUsername = withoutSticky.startsWith("user-") ? withoutSticky : `user-${withoutSticky}`;
265
259
  return `${baseUsername}-session-${sessionId}-sessionduration-${sessionDuration}`;
266
260
  }
267
261
  function syncProxyEnv(config) {
@@ -358,18 +352,13 @@ function resolvePolicy(options) {
358
352
  return undefined;
359
353
  }
360
354
  function resolveProxyProvider(policy) {
361
- return (policy.provider ??
362
- process.env[DEFAULT_PROXY_PROVIDER_ENV]?.trim().toLowerCase() ??
363
- "custom");
355
+ return (policy.provider ?? process.env[DEFAULT_PROXY_PROVIDER_ENV]?.trim().toLowerCase() ?? "custom");
364
356
  }
365
357
  function resolveSmartproxyCountry(policy) {
366
- return (policy.geo?.country ??
367
- process.env[DEFAULT_PROXY_COUNTRY_ENV]?.trim().toUpperCase() ??
368
- undefined);
358
+ return (policy.geo?.country ?? process.env[DEFAULT_PROXY_COUNTRY_ENV]?.trim().toUpperCase() ?? undefined);
369
359
  }
370
360
  function resolveSmartproxyLifetime(policy) {
371
- const configuredLifetime = policy.session?.lifetimeMinutes ??
372
- readPositiveNumberEnv(DEFAULT_PROXY_LIFETIME_ENV, 30);
361
+ const configuredLifetime = policy.session?.lifetimeMinutes ?? readPositiveNumberEnv(DEFAULT_PROXY_LIFETIME_ENV, 30);
373
362
  return Math.min(SMARTPROXY_MAX_LIFETIME_MINUTES, Math.max(1, Math.floor(configuredLifetime)));
374
363
  }
375
364
  function readPositiveNumberEnv(name, fallback) {
@@ -389,9 +378,7 @@ function selectProxyPoolIndex(poolSize, attempt = 0) {
389
378
  if (poolSize <= 1) {
390
379
  return 0;
391
380
  }
392
- const normalizedAttempt = Number.isFinite(attempt)
393
- ? Math.max(0, Math.floor(attempt))
394
- : 0;
381
+ const normalizedAttempt = Number.isFinite(attempt) ? Math.max(0, Math.floor(attempt)) : 0;
395
382
  return normalizedAttempt % poolSize;
396
383
  }
397
384
  function buildSmartproxyCacheKey(policy, affinityKey, lifetimeMinutes) {
@@ -400,9 +387,7 @@ function buildSmartproxyCacheKey(policy, affinityKey, lifetimeMinutes) {
400
387
  provider: "smartproxy",
401
388
  country: resolveSmartproxyCountry(policy),
402
389
  affinity: policy.session?.affinity ?? "request",
403
- affinityKey: (policy.session?.affinity ?? "request") === "request"
404
- ? undefined
405
- : affinityKey,
390
+ affinityKey: (policy.session?.affinity ?? "request") === "request" ? undefined : affinityKey,
406
391
  lifetimeMinutes,
407
392
  poolSize,
408
393
  });
@@ -499,9 +484,7 @@ async function allocateSmartproxyShared(cacheKey, policy, appKey, lifetimeMinute
499
484
  if (acquired === "OK") {
500
485
  try {
501
486
  return await allocateAndStoreSmartproxyPool(cacheKey, policy, appKey, lifetimeMinutes, startedAt, {
502
- cacheStatus: options.background
503
- ? "soft_stale_refresh"
504
- : "allocator",
487
+ cacheStatus: options.background ? "soft_stale_refresh" : "allocator",
505
488
  redis,
506
489
  poolKey,
507
490
  });
@@ -526,8 +509,7 @@ async function allocateSmartproxyShared(cacheKey, policy, appKey, lifetimeMinute
526
509
  if (typeof pttl === "number" && pttl <= 0) {
527
510
  continue;
528
511
  }
529
- if (Date.now() - startedAt >
530
- SMARTPROXY_LOCK_POLL_MAX_MS - SMARTPROXY_DEADLINE_MARGIN_MS) {
512
+ if (Date.now() - startedAt > SMARTPROXY_LOCK_POLL_MAX_MS - SMARTPROXY_DEADLINE_MARGIN_MS) {
531
513
  break;
532
514
  }
533
515
  await sleep(Math.min(500, Math.max(50, typeof pttl === "number" ? pttl : 100)));
@@ -559,7 +541,7 @@ function sleep(ms, signal) {
559
541
  });
560
542
  }
561
543
  function smartproxyAllocatorDeadlineMs() {
562
- return (smartproxyAllocatorDeadlineMsForTests ?? SMARTPROXY_ALLOCATOR_DEADLINE_MS);
544
+ return smartproxyAllocatorDeadlineMsForTests ?? SMARTPROXY_ALLOCATOR_DEADLINE_MS;
563
545
  }
564
546
  function createDeadlineAbortController(deadlineAt) {
565
547
  const controller = new AbortController();
@@ -649,9 +631,7 @@ async function allocateAndStoreSmartproxyPool(cacheKey, policy, appKey, lifetime
649
631
  }
650
632
  }
651
633
  const allocatorMs = Math.max(0, Date.now() - allocatorStartedAt);
652
- const allocatorAttempts = allocation?.attempt ??
653
- lastFailure?.attempt ??
654
- SMARTPROXY_ALLOCATOR_MAX_ATTEMPTS;
634
+ const allocatorAttempts = allocation?.attempt ?? lastFailure?.attempt ?? SMARTPROXY_ALLOCATOR_MAX_ATTEMPTS;
655
635
  const allocatorBodyClass = lastFailure?.bodyClass ?? allocation?.bodyClass ?? "usable_proxy_endpoints";
656
636
  const allocatorStatus = lastFailure ? lastFailure.status : allocation?.status;
657
637
  if (!allocation) {
@@ -804,7 +784,9 @@ function buildSmartproxyAllocatorUrl(policy, appKey, lifetimeMinutes, poolSize)
804
784
  if (country) {
805
785
  params.set("cc", country);
806
786
  }
807
- return `https://www.smartproxy.org/web_v1/ip/get-ip-v3?${params.toString()}`;
787
+ // www.smartproxy.org stopped serving the extraction API on 2026-07-21 (the
788
+ // old path 404s into the marketing site); the API lives on the api host.
789
+ return `https://api.smartproxy.org/web_v1/ip/get-ip-v3?${params.toString()}`;
808
790
  }
809
791
  function parseSmartproxyAllocatorProxies(body) {
810
792
  const trimmed = body.trim();
@@ -813,12 +795,8 @@ function parseSmartproxyAllocatorProxies(body) {
813
795
  }
814
796
  try {
815
797
  const parsed = JSON.parse(trimmed);
816
- const data = parsed && typeof parsed === "object" && "data" in parsed
817
- ? parsed.data
818
- : undefined;
819
- const list = data && typeof data === "object" && "list" in data
820
- ? data.list
821
- : undefined;
798
+ const data = parsed && typeof parsed === "object" && "data" in parsed ? parsed.data : undefined;
799
+ const list = data && typeof data === "object" && "list" in data ? data.list : undefined;
822
800
  if (Array.isArray(list)) {
823
801
  return list
824
802
  .map((item) => {
@@ -826,8 +804,7 @@ function parseSmartproxyAllocatorProxies(body) {
826
804
  return null;
827
805
  }
828
806
  const ip = "ip" in item && typeof item.ip === "string" ? item.ip : "";
829
- const port = "port" in item &&
830
- (typeof item.port === "string" || typeof item.port === "number")
807
+ const port = "port" in item && (typeof item.port === "string" || typeof item.port === "number")
831
808
  ? item.port
832
809
  : "";
833
810
  return ip && port ? `http://${ip}:${port}` : null;
@@ -1,4 +1,4 @@
1
- import { type JsonValue } from "./contract-json";
2
- import type { SchemaLike } from "./types";
1
+ import { type JsonValue } from "./contract-json.js";
2
+ import type { SchemaLike } from "./types.js";
3
3
  export declare function describeSchema(schema: SchemaLike): JsonValue;
4
4
  export declare function serializeSmsMatcher(value: Record<string, unknown>): Record<string, unknown>;
@@ -1,6 +1,6 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { z } from "zod";
3
- import { canonicalJson, compactObject, isRecord, toJsonValue, } from "./contract-json";
3
+ import { canonicalJson, compactObject, isRecord, toJsonValue, } from "./contract-json.js";
4
4
  export function describeSchema(schema) {
5
5
  if (isZodSchema(schema)) {
6
6
  const jsonSchema = zodJsonSchema(schema);
@@ -9,9 +9,7 @@ export function describeSchema(schema) {
9
9
  vendor: "zod",
10
10
  typeName: getSchemaTypeName(schema),
11
11
  jsonSchema,
12
- jsonSchemaHash: jsonSchema === undefined
13
- ? undefined
14
- : digest(canonicalJson(jsonSchema)),
12
+ jsonSchemaHash: jsonSchema === undefined ? undefined : digest(canonicalJson(jsonSchema)),
15
13
  });
16
14
  }
17
15
  const standard = isRecord(schema) ? schema["~standard"] : undefined;
@@ -20,8 +18,7 @@ export function describeSchema(schema) {
20
18
  kind: "schema",
21
19
  standard: "standard-schema-v1",
22
20
  vendor: typeof standard.vendor === "string" ? standard.vendor : "unknown",
23
- version: typeof standard.version === "number" ||
24
- typeof standard.version === "string"
21
+ version: typeof standard.version === "number" || typeof standard.version === "string"
25
22
  ? standard.version
26
23
  : undefined,
27
24
  });
@@ -1,5 +1,5 @@
1
- import type { JsonValue } from "./contract-json";
2
- import type { ProviderDefinition } from "./types";
1
+ import type { JsonValue } from "./contract-json.js";
2
+ import type { ProviderDefinition } from "./types.js";
3
3
  export declare const PROVIDER_CONTRACT_SCHEMA_VERSION = "2026-06-23";
4
4
  export interface ProviderContractSnapshot {
5
5
  readonly schemaVersion: typeof PROVIDER_CONTRACT_SCHEMA_VERSION;