@apifuse/provider-sdk 2.2.0-beta.1 → 2.2.0-beta.11

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 (261) hide show
  1. package/AUTHORING.md +106 -0
  2. package/CHANGELOG.md +41 -0
  3. package/README.md +5 -1
  4. package/SUBMISSION.md +1 -1
  5. package/bin/apifuse-check.ts +44 -59
  6. package/bin/apifuse-create.ts +1 -1
  7. package/bin/apifuse-dev.ts +27 -52
  8. package/bin/apifuse-pack-check.ts +14 -0
  9. package/bin/apifuse-pack-smoke.ts +22 -81
  10. package/bin/apifuse-pack-types.ts +266 -0
  11. package/bin/apifuse-perf.ts +45 -127
  12. package/bin/apifuse-record.ts +53 -70
  13. package/bin/apifuse-submit-check.ts +510 -45
  14. package/bin/apifuse-sync-assets.ts +117 -0
  15. package/bin/apifuse.ts +1 -1
  16. package/bin/submit-check-delimited-text.ts +50 -0
  17. package/bin/submit-check-xml-semantics.ts +204 -0
  18. package/bin/submit-check-xml.ts +134 -0
  19. package/dist/auth-turn/index.d.ts +3 -3
  20. package/dist/auth.d.ts +2 -2
  21. package/dist/auth.js +9 -18
  22. package/dist/ceremonies/index.d.ts +1 -1
  23. package/dist/ceremonies/index.js +8 -18
  24. package/dist/cli/commands.d.ts +1 -1
  25. package/dist/cli/commands.js +8 -0
  26. package/dist/cli/create.d.ts +3 -0
  27. package/dist/cli/create.js +34 -35
  28. package/dist/cli/prompt-assets.d.ts +80 -0
  29. package/dist/cli/prompt-assets.js +743 -0
  30. package/dist/cli/templates/provider/AGENTS.md.tpl +17 -8
  31. package/dist/config/loader.d.ts +149 -8
  32. package/dist/config/loader.js +378 -89
  33. package/dist/contract-serialization.d.ts +2 -2
  34. package/dist/contract-serialization.js +3 -6
  35. package/dist/contract-types.d.ts +2 -2
  36. package/dist/contract.d.ts +3 -3
  37. package/dist/contract.js +4 -6
  38. package/dist/define.d.ts +8 -1
  39. package/dist/define.js +119 -122
  40. package/dist/dev.d.ts +1 -1
  41. package/dist/dev.js +1 -1
  42. package/dist/errors.d.ts +4 -1
  43. package/dist/errors.js +48 -0
  44. package/dist/i18n/catalog.d.ts +2 -2
  45. package/dist/i18n/catalog.js +4 -10
  46. package/dist/i18n/index.d.ts +2 -2
  47. package/dist/i18n/index.js +2 -2
  48. package/dist/i18n/keys.d.ts +2 -2
  49. package/dist/index.d.ts +44 -42
  50. package/dist/index.js +39 -37
  51. package/dist/lint.js +8 -15
  52. package/dist/provider.d.ts +11 -11
  53. package/dist/provider.js +9 -9
  54. package/dist/public-schema-field-lint.d.ts +1 -1
  55. package/dist/recipes/gov-api.js +1 -1
  56. package/dist/runtime/auth-flow.d.ts +1 -1
  57. package/dist/runtime/auth-flow.js +3 -3
  58. package/dist/runtime/browser.d.ts +1 -1
  59. package/dist/runtime/browser.js +15 -29
  60. package/dist/runtime/cache.d.ts +1 -1
  61. package/dist/runtime/cache.js +4 -8
  62. package/dist/runtime/choice.d.ts +1 -1
  63. package/dist/runtime/choice.js +31 -35
  64. package/dist/runtime/credential.d.ts +1 -1
  65. package/dist/runtime/credential.js +1 -1
  66. package/dist/runtime/env.d.ts +1 -1
  67. package/dist/runtime/executor.d.ts +1 -1
  68. package/dist/runtime/executor.js +15 -3
  69. package/dist/runtime/http.d.ts +2 -2
  70. package/dist/runtime/http.js +144 -348
  71. package/dist/runtime/insights.d.ts +1 -1
  72. package/dist/runtime/insights.js +6 -13
  73. package/dist/runtime/instrumentation.d.ts +2 -2
  74. package/dist/runtime/instrumentation.js +56 -19
  75. package/dist/runtime/keyring.js +1 -1
  76. package/dist/runtime/namespace.js +1 -1
  77. package/dist/runtime/otlp.d.ts +1 -1
  78. package/dist/runtime/perf.d.ts +1 -1
  79. package/dist/runtime/provider.d.ts +1 -1
  80. package/dist/runtime/provider.js +1 -2
  81. package/dist/runtime/proxy-errors.d.ts +1 -1
  82. package/dist/runtime/proxy-errors.js +9 -7
  83. package/dist/runtime/proxy-nodemaven.d.ts +35 -0
  84. package/dist/runtime/proxy-nodemaven.js +128 -0
  85. package/dist/runtime/proxy-retry-policy.d.ts +40 -0
  86. package/dist/runtime/proxy-retry-policy.js +326 -0
  87. package/dist/runtime/proxy-telemetry.d.ts +2 -1
  88. package/dist/runtime/proxy-telemetry.js +55 -52
  89. package/dist/runtime/redis.d.ts +1 -1
  90. package/dist/runtime/redis.js +2 -4
  91. package/dist/runtime/request-options.d.ts +1 -1
  92. package/dist/runtime/secrets.d.ts +27 -0
  93. package/dist/runtime/secrets.js +51 -0
  94. package/dist/runtime/state.d.ts +2 -2
  95. package/dist/runtime/state.js +15 -4
  96. package/dist/runtime/stealth.d.ts +2 -2
  97. package/dist/runtime/stealth.js +108 -212
  98. package/dist/runtime/stt.d.ts +1 -1
  99. package/dist/runtime/stt.js +11 -15
  100. package/dist/runtime/trace.d.ts +2 -2
  101. package/dist/runtime/trace.js +2 -4
  102. package/dist/runtime/waterfall.d.ts +1 -1
  103. package/dist/schema.d.ts +1 -1
  104. package/dist/schema.js +7 -15
  105. package/dist/serve.d.ts +1 -1
  106. package/dist/serve.js +1 -1
  107. package/dist/server/index.d.ts +7 -7
  108. package/dist/server/index.js +6 -6
  109. package/dist/server/self-test-redaction.d.ts +1 -1
  110. package/dist/server/self-test-redaction.js +1 -1
  111. package/dist/server/self-test.d.ts +104 -3
  112. package/dist/server/self-test.js +673 -115
  113. package/dist/server/serve.d.ts +105 -4
  114. package/dist/server/serve.js +588 -80
  115. package/dist/server/types.d.ts +10 -9
  116. package/dist/server/types.js +3 -7
  117. package/dist/stateful/errors.d.ts +14 -0
  118. package/dist/stateful/errors.js +14 -0
  119. package/dist/stateful/http-provider-event-emitter.d.ts +40 -0
  120. package/dist/stateful/http-provider-event-emitter.js +237 -0
  121. package/dist/stateful/http-session-owner-registry.d.ts +44 -0
  122. package/dist/stateful/http-session-owner-registry.js +210 -0
  123. package/dist/stateful/index.d.ts +18 -0
  124. package/dist/stateful/index.js +18 -0
  125. package/dist/stateful/provider-event-delivery-failures.d.ts +32 -0
  126. package/dist/stateful/provider-event-delivery-failures.js +43 -0
  127. package/dist/stateful/provider-event-pipeline-metrics.d.ts +46 -0
  128. package/dist/stateful/provider-event-pipeline-metrics.js +48 -0
  129. package/dist/stateful/provider-event-pipeline.d.ts +50 -0
  130. package/dist/stateful/provider-event-pipeline.js +1 -0
  131. package/dist/stateful/provider-events.d.ts +101 -0
  132. package/dist/stateful/provider-events.js +289 -0
  133. package/dist/stateful/session-key.d.ts +15 -0
  134. package/dist/stateful/session-key.js +86 -0
  135. package/dist/stateful/stateful-provider-adapter-context.d.ts +5 -0
  136. package/dist/stateful/stateful-provider-adapter-context.js +42 -0
  137. package/dist/stateful/stateful-provider-adapter-metrics.d.ts +15 -0
  138. package/dist/stateful/stateful-provider-adapter-metrics.js +21 -0
  139. package/dist/stateful/stateful-provider-adapter.d.ts +98 -0
  140. package/dist/stateful/stateful-provider-adapter.js +287 -0
  141. package/dist/stateful/stateful-provider-observability.d.ts +62 -0
  142. package/dist/stateful/stateful-provider-observability.js +161 -0
  143. package/dist/stateful/stateful-provider-owner-forwarder.d.ts +41 -0
  144. package/dist/stateful/stateful-provider-owner-forwarder.js +207 -0
  145. package/dist/stateful/stateful-provider-runtime-context.d.ts +32 -0
  146. package/dist/stateful/stateful-provider-runtime-context.js +60 -0
  147. package/dist/stateful/stateful-provider-runtime-executor.d.ts +34 -0
  148. package/dist/stateful/stateful-provider-runtime-executor.js +52 -0
  149. package/dist/stateful/stateful-provider-session-routing.d.ts +71 -0
  150. package/dist/stateful/stateful-provider-session-routing.js +353 -0
  151. package/dist/stateful/stateful-provider-session-runtime.d.ts +98 -0
  152. package/dist/stateful/stateful-provider-session-runtime.js +245 -0
  153. package/dist/stateful-signing.d.ts +18 -0
  154. package/dist/stateful-signing.js +27 -0
  155. package/dist/stealth/profiles.d.ts +1 -1
  156. package/dist/stealth/profiles.js +5 -14
  157. package/dist/stream.d.ts +1 -1
  158. package/dist/testing/index.d.ts +2 -2
  159. package/dist/testing/index.js +2 -2
  160. package/dist/testing/run.d.ts +1 -1
  161. package/dist/testing/run.js +7 -14
  162. package/dist/types.d.ts +87 -1
  163. package/dist/user-input.d.ts +30 -0
  164. package/dist/user-input.js +66 -0
  165. package/package.json +14 -5
  166. package/src/auth-turn/index.ts +1 -1
  167. package/src/auth.ts +28 -86
  168. package/src/ceremonies/index.ts +24 -78
  169. package/src/cli/commands.ts +10 -0
  170. package/src/cli/create.ts +42 -35
  171. package/src/cli/prompt-assets.ts +865 -0
  172. package/src/cli/templates/provider/AGENTS.md.tpl +17 -8
  173. package/src/config/loader.ts +543 -208
  174. package/src/contract-serialization.ts +5 -11
  175. package/src/contract-types.ts +2 -2
  176. package/src/contract.ts +12 -28
  177. package/src/define.ts +247 -505
  178. package/src/dev.ts +4 -9
  179. package/src/errors.ts +58 -5
  180. package/src/i18n/catalog.ts +10 -32
  181. package/src/i18n/index.ts +2 -2
  182. package/src/i18n/keys.ts +5 -11
  183. package/src/index.ts +49 -42
  184. package/src/lint.ts +89 -159
  185. package/src/provider.ts +15 -11
  186. package/src/public-schema-field-lint.ts +7 -33
  187. package/src/recipes/gov-api.ts +2 -5
  188. package/src/runtime/auth-flow.ts +5 -7
  189. package/src/runtime/browser.ts +64 -187
  190. package/src/runtime/cache.ts +20 -67
  191. package/src/runtime/choice.ts +79 -132
  192. package/src/runtime/credential.ts +2 -2
  193. package/src/runtime/env.ts +1 -1
  194. package/src/runtime/executor.ts +23 -20
  195. package/src/runtime/http.ts +195 -559
  196. package/src/runtime/insights.ts +15 -53
  197. package/src/runtime/instrumentation.ts +78 -65
  198. package/src/runtime/keyring.ts +7 -19
  199. package/src/runtime/namespace.ts +2 -7
  200. package/src/runtime/otlp.ts +12 -23
  201. package/src/runtime/perf.ts +1 -1
  202. package/src/runtime/provider.ts +4 -9
  203. package/src/runtime/proxy-errors.ts +29 -42
  204. package/src/runtime/proxy-nodemaven.ts +178 -0
  205. package/src/runtime/proxy-retry-policy.ts +469 -0
  206. package/src/runtime/proxy-telemetry.ts +79 -77
  207. package/src/runtime/redis.ts +4 -12
  208. package/src/runtime/request-options.ts +4 -13
  209. package/src/runtime/secrets.ts +64 -0
  210. package/src/runtime/state.ts +41 -110
  211. package/src/runtime/stealth.ts +162 -377
  212. package/src/runtime/stt.ts +38 -94
  213. package/src/runtime/trace.ts +14 -44
  214. package/src/runtime/waterfall.ts +5 -18
  215. package/src/schema.ts +23 -84
  216. package/src/serve.ts +1 -1
  217. package/src/server/index.ts +24 -7
  218. package/src/server/self-test-redaction.ts +2 -2
  219. package/src/server/self-test.ts +857 -132
  220. package/src/server/serve.ts +859 -266
  221. package/src/server/types.ts +7 -19
  222. package/src/stateful/README.md +146 -0
  223. package/src/stateful/errors.ts +23 -0
  224. package/src/stateful/http-provider-event-emitter.ts +314 -0
  225. package/src/stateful/http-session-owner-registry.ts +306 -0
  226. package/src/stateful/index.ts +18 -0
  227. package/src/stateful/provider-event-delivery-failures.ts +80 -0
  228. package/src/stateful/provider-event-pipeline-metrics.ts +95 -0
  229. package/src/stateful/provider-event-pipeline.ts +61 -0
  230. package/src/stateful/provider-events.ts +462 -0
  231. package/src/stateful/session-key.ts +111 -0
  232. package/src/stateful/stateful-provider-adapter-context.ts +59 -0
  233. package/src/stateful/stateful-provider-adapter-metrics.ts +48 -0
  234. package/src/stateful/stateful-provider-adapter.ts +562 -0
  235. package/src/stateful/stateful-provider-observability.ts +261 -0
  236. package/src/stateful/stateful-provider-owner-forwarder.ts +279 -0
  237. package/src/stateful/stateful-provider-runtime-context.ts +92 -0
  238. package/src/stateful/stateful-provider-runtime-executor.ts +96 -0
  239. package/src/stateful/stateful-provider-session-routing.ts +555 -0
  240. package/src/stateful/stateful-provider-session-runtime.ts +403 -0
  241. package/src/stateful-signing.ts +46 -0
  242. package/src/stealth/profiles.ts +10 -26
  243. package/src/stream.ts +8 -19
  244. package/src/testing/index.ts +2 -2
  245. package/src/testing/run.ts +19 -67
  246. package/src/types.ts +88 -1
  247. package/src/user-input.ts +118 -0
  248. package/dist/cli/templates/provider/CLAUDE.md.tpl +0 -1
  249. package/src/cli/templates/provider/CLAUDE.md.tpl +0 -1
  250. /package/dist/cli/templates/provider/{skills → .agents/skills}/fixtures-and-recording/SKILL.md.tpl +0 -0
  251. /package/dist/cli/templates/provider/{skills → .agents/skills}/health-checks-and-fail-closed/SKILL.md.tpl +0 -0
  252. /package/dist/cli/templates/provider/{skills → .agents/skills}/normalization-standards/SKILL.md.tpl +0 -0
  253. /package/dist/cli/templates/provider/{skills → .agents/skills}/pagination-and-counts/SKILL.md.tpl +0 -0
  254. /package/dist/cli/templates/provider/{skills → .agents/skills}/upstream-contract-verification/SKILL.md.tpl +0 -0
  255. /package/dist/cli/templates/provider/{skills → .agents/skills}/upstream-notes/README.md.tpl +0 -0
  256. /package/src/cli/templates/provider/{skills → .agents/skills}/fixtures-and-recording/SKILL.md.tpl +0 -0
  257. /package/src/cli/templates/provider/{skills → .agents/skills}/health-checks-and-fail-closed/SKILL.md.tpl +0 -0
  258. /package/src/cli/templates/provider/{skills → .agents/skills}/normalization-standards/SKILL.md.tpl +0 -0
  259. /package/src/cli/templates/provider/{skills → .agents/skills}/pagination-and-counts/SKILL.md.tpl +0 -0
  260. /package/src/cli/templates/provider/{skills → .agents/skills}/upstream-contract-verification/SKILL.md.tpl +0 -0
  261. /package/src/cli/templates/provider/{skills → .agents/skills}/upstream-notes/README.md.tpl +0 -0
@@ -0,0 +1,18 @@
1
+ export declare const STATEFUL_SIGNATURE_HEADER = "x-apifuse-stateful-signature";
2
+ export declare const STATEFUL_TIMESTAMP_HEADER = "x-apifuse-stateful-timestamp";
3
+ export declare const STATEFUL_NONCE_HEADER = "x-apifuse-stateful-nonce";
4
+ export type StatefulSigningInput = {
5
+ readonly secret: string;
6
+ readonly timestamp: string;
7
+ readonly rawBody: string;
8
+ readonly method: string;
9
+ readonly path: string;
10
+ readonly nonce: string;
11
+ };
12
+ export declare function signStatefulRequestBody(input: StatefulSigningInput): string;
13
+ export declare function verifyStatefulRequestSignature(input: StatefulSigningInput & {
14
+ readonly signature: string;
15
+ }): boolean;
16
+ export declare function statefulSignedHeaders(input: Omit<StatefulSigningInput, "nonce"> & {
17
+ readonly nonce?: string;
18
+ }): Record<string, string>;
@@ -0,0 +1,27 @@
1
+ import { createHmac, randomUUID, timingSafeEqual } from "node:crypto";
2
+ export const STATEFUL_SIGNATURE_HEADER = "x-apifuse-stateful-signature";
3
+ export const STATEFUL_TIMESTAMP_HEADER = "x-apifuse-stateful-timestamp";
4
+ export const STATEFUL_NONCE_HEADER = "x-apifuse-stateful-nonce";
5
+ export function signStatefulRequestBody(input) {
6
+ return `v1=${createHmac("sha256", input.secret)
7
+ .update(`v1:${input.method.toUpperCase()}:${input.path}:${input.timestamp}:${input.nonce}.${input.rawBody}`)
8
+ .digest("hex")}`;
9
+ }
10
+ export function verifyStatefulRequestSignature(input) {
11
+ return safeEqualAscii(input.signature, signStatefulRequestBody(input));
12
+ }
13
+ export function statefulSignedHeaders(input) {
14
+ const nonce = input.nonce ?? randomUUID();
15
+ return {
16
+ [STATEFUL_SIGNATURE_HEADER]: signStatefulRequestBody({ ...input, nonce }),
17
+ [STATEFUL_TIMESTAMP_HEADER]: input.timestamp,
18
+ [STATEFUL_NONCE_HEADER]: nonce,
19
+ };
20
+ }
21
+ function safeEqualAscii(actual, expected) {
22
+ const actualBytes = Buffer.from(actual);
23
+ const expectedBytes = Buffer.from(expected);
24
+ if (actualBytes.byteLength !== expectedBytes.byteLength)
25
+ return false;
26
+ return timingSafeEqual(actualBytes, expectedBytes);
27
+ }
@@ -1,4 +1,4 @@
1
- import type { StealthProfile } from "../types";
1
+ import type { StealthProfile } from "../types.js";
2
2
  export declare function generateLayer2Headers(profile: StealthProfile): Record<string, string>;
3
3
  export declare function getStealthProfile(name: string): StealthProfile;
4
4
  export declare function listStealthProfiles(): string[];
@@ -1,4 +1,4 @@
1
- import { SDKError } from "../errors";
1
+ import { SDKError } from "../errors.js";
2
2
  const CHROMIUM_HEADER_ORDER = [
3
3
  ":method",
4
4
  ":authority",
@@ -74,12 +74,8 @@ function createProfile(name, definition) {
74
74
  tlsClientIdentifier: definition.tlsClientIdentifier,
75
75
  ja3: definition.ja3,
76
76
  ja4: definition.ja4,
77
- h2Settings: definition.h2Settings
78
- ? { ...definition.h2Settings }
79
- : undefined,
80
- headerOrder: definition.headerOrder
81
- ? [...definition.headerOrder]
82
- : undefined,
77
+ h2Settings: definition.h2Settings ? { ...definition.h2Settings } : undefined,
78
+ headerOrder: definition.headerOrder ? [...definition.headerOrder] : undefined,
83
79
  };
84
80
  }
85
81
  function extractBrowserMajorVersion(profile) {
@@ -120,9 +116,7 @@ export function generateLayer2Headers(profile) {
120
116
  : `"Chromium";v="${majorVersion}", "Google Chrome";v="${majorVersion}", "Not)A;Brand";v="99"`;
121
117
  headers["Sec-Ch-Ua-Platform"] = toPlatformHeaderValue(profile.platform);
122
118
  headers["Sec-Ch-Ua-Mobile"] =
123
- profile.platform === "android" || profile.platform === "ios"
124
- ? "?1"
125
- : "?0";
119
+ profile.platform === "android" || profile.platform === "ios" ? "?1" : "?0";
126
120
  }
127
121
  return headers;
128
122
  }
@@ -252,8 +246,5 @@ export function getStealthProfile(name) {
252
246
  };
253
247
  }
254
248
  export function listStealthProfiles() {
255
- return [
256
- ...Object.keys(STEALTH_PROFILES),
257
- ...Object.keys(STEALTH_PROFILE_ALIASES),
258
- ];
249
+ return [...Object.keys(STEALTH_PROFILES), ...Object.keys(STEALTH_PROFILE_ALIASES)];
259
250
  }
package/dist/stream.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { SseMessage } from "./types";
1
+ import type { SseMessage } from "./types.js";
2
2
  export interface SseEvent<TData = unknown> {
3
3
  event: string;
4
4
  data: TData;
@@ -1,2 +1,2 @@
1
- export { describeTransform, snapshotTransform, toMatchShape } from "./helpers";
2
- export { runStandardTests } from "./run";
1
+ export { describeTransform, snapshotTransform, toMatchShape } from "./helpers.js";
2
+ export { runStandardTests } from "./run.js";
@@ -1,2 +1,2 @@
1
- export { describeTransform, snapshotTransform, toMatchShape } from "./helpers";
2
- export { runStandardTests } from "./run";
1
+ export { describeTransform, snapshotTransform, toMatchShape } from "./helpers.js";
2
+ export { runStandardTests } from "./run.js";
@@ -1,4 +1,4 @@
1
- import type { AuthMode, ProviderDefinition } from "../types";
1
+ import type { AuthMode, ProviderDefinition } from "../types.js";
2
2
  export interface StandardTestsManifest {
3
3
  id?: string;
4
4
  displayName?: string;
@@ -1,19 +1,14 @@
1
1
  import { describe, expect, it } from "bun:test";
2
- import { createProviderCache } from "../runtime/cache";
3
- import { createTestProviderChoiceContext } from "../runtime/choice";
4
- import { createMemoryProviderRuntimeState } from "../runtime/state";
5
- import { createUnsupportedSttClient } from "../runtime/stt";
6
- import { safeParseSchemaSync } from "../schema";
2
+ import { createProviderCache } from "../runtime/cache.js";
3
+ import { createTestProviderChoiceContext } from "../runtime/choice.js";
4
+ import { createMemoryProviderRuntimeState } from "../runtime/state.js";
5
+ import { createUnsupportedSttClient } from "../runtime/stt.js";
6
+ import { safeParseSchemaSync } from "../schema.js";
7
7
  // Mirrors CONNECTOR_ID_REGEX in ../define.ts, which defineProvider() enforces.
8
8
  // A single lowercase segment (no hyphen) is a valid id, so the trailing group
9
9
  // is optional (`*`), matching providers like `kakaomap`, `kstartup`, `triple`.
10
10
  const CONNECTOR_ID_REGEX = /^[a-z][a-z0-9]*(-[a-z][a-z0-9]*)*$/;
11
- const VALID_AUTH_MODES = [
12
- "none",
13
- "platform-managed",
14
- "credentials",
15
- "oauth2",
16
- ];
11
+ const VALID_AUTH_MODES = ["none", "platform-managed", "credentials", "oauth2"];
17
12
  const UPDATE_SNAPSHOT_ARGS = new Set(["-u", "--update-snapshots"]);
18
13
  function isFixtureEnvelope(value) {
19
14
  return (value !== null &&
@@ -60,9 +55,7 @@ function inferFixtureDir(providerId) {
60
55
  .map((line) => line.match(/\(?((?:file:\/\/)?[^():]+\.test\.ts)/)?.[1])
61
56
  .find((file) => file !== undefined);
62
57
  if (testFile) {
63
- const pathname = testFile.startsWith("file://")
64
- ? new URL(testFile).pathname
65
- : testFile;
58
+ const pathname = testFile.startsWith("file://") ? new URL(testFile).pathname : testFile;
66
59
  return `${pathname.replace(/\/[^/]+$/, "")}/../__fixtures__`;
67
60
  }
68
61
  return `providers/${providerId}/__fixtures__`;
package/dist/types.d.ts CHANGED
@@ -650,7 +650,25 @@ export type ConnectionMode = AuthMode;
650
650
  export type ProviderReviewed = "first-party" | "community" | "staging";
651
651
  export type ProviderAccessVisibility = "public" | "early_access";
652
652
  export type ProviderProxyMode = "disabled" | "optional" | "required";
653
- export type ProviderProxyProvider = "smartproxy" | "decodo" | "custom";
653
+ /**
654
+ * Proxy egress vendors. These are FOUR DISTINCT services — do not conflate them
655
+ * (a common mistake because the names collide with a well-known rebrand):
656
+ *
657
+ * - `smartproxy` — **api.smartproxy.org**, a residential proxy with an IP
658
+ * *extraction/allocation* API (app_key → a pool of raw `ip:port` CONNECT
659
+ * endpoints). This is our own vendor. It is NOT the company formerly named
660
+ * "Smartproxy". Credentials: `APIFUSE__PROXY__SMARTPROXY_APP_KEY`.
661
+ * - `nodemaven` — **gate.nodemaven.com**, a *gateway* proxy with static
662
+ * credentials; geo/session encoded in the username, no allocation API.
663
+ * - `decodo` — **decodo.com**, the *gateway* proxy that was named "Smartproxy"
664
+ * (smartproxy.com) before its 2025 rebrand to Decodo. Sticky sessions via
665
+ * username params. A different company from `smartproxy` above.
666
+ * **@deprecated** — unused; no managed adapter. Use `smartproxy`/`nodemaven`,
667
+ * or the `APIFUSE__PROXY__URL` bring-your-own escape hatch.
668
+ * - `custom` — **@deprecated** bring-your-own static proxy URL marker. The
669
+ * `APIFUSE__PROXY__URL` env still works without declaring this value.
670
+ */
671
+ export type ProviderProxyProvider = "smartproxy" | "nodemaven" | "decodo" | "custom";
654
672
  export type ProviderProxySessionAffinity = "request" | "operation" | "auth-flow" | "connection";
655
673
  export interface ProviderProxyPolicy {
656
674
  /**
@@ -658,7 +676,18 @@ export interface ProviderProxyPolicy {
658
676
  * certificate verification, and vendor allocator endpoints are SDK-owned.
659
677
  */
660
678
  mode: ProviderProxyMode;
679
+ /**
680
+ * @deprecated Use `providers: [...]` to declare an ordered vendor fallback
681
+ * chain. A single-element `providers` list is equivalent to this field.
682
+ */
661
683
  provider?: ProviderProxyProvider;
684
+ /**
685
+ * Ordered proxy-vendor fallback chain. The SDK tries each vendor in order and
686
+ * fails over to the next when a vendor lacks credentials or its allocation /
687
+ * transport is exhausted. When omitted, `provider` (or the platform default)
688
+ * is used as a single-vendor chain.
689
+ */
690
+ providers?: ProviderProxyProvider[];
662
691
  geo?: {
663
692
  /** ISO 3166-1 alpha-2 country code, for example KR or US. */
664
693
  country?: Iso3166Alpha2CountryCode;
@@ -1418,6 +1447,19 @@ export interface OperationContractMetadata {
1418
1447
  deprecation?: OperationDeprecationMetadata;
1419
1448
  }
1420
1449
  export interface OperationDefinition<TInput extends SchemaLike = SchemaLike, TOutput extends SchemaLike = SchemaLike> {
1450
+ /**
1451
+ * Short English display title for the operation. The SDK passes it through
1452
+ * verbatim; the APIFuse registry derives the operation's en locale title
1453
+ * baseline from it (`docs.titleKey` remains available as an explicit key
1454
+ * override).
1455
+ */
1456
+ title?: string;
1457
+ /**
1458
+ * Raw English operation description. The SDK passes it through verbatim;
1459
+ * keyed descriptions via `descriptionKey` remain the primary flow, and
1460
+ * provider lint rules for raw prose descriptions still apply.
1461
+ */
1462
+ description?: string;
1421
1463
  descriptionKey?: ProviderLocaleKeyInput;
1422
1464
  docs?: OperationDocMeta;
1423
1465
  whenToUseKeys?: readonly ProviderLocaleKeyInput[];
@@ -1447,10 +1489,54 @@ export interface OperationDefinition<TInput extends SchemaLike = SchemaLike, TOu
1447
1489
  healthCheck?: HealthCheckSuite<InferSchemaOutput<TInput>, InferSchemaOutput<TOutput>>;
1448
1490
  healthCheckUnsupported?: HealthCheckUnsupported;
1449
1491
  }
1492
+ /**
1493
+ * Author-declared deployment overrides accepted as the optional top-level
1494
+ * `deployment` key on `defineProvider()`.
1495
+ *
1496
+ * The SDK passes this object through VERBATIM onto the returned provider
1497
+ * definition — it is typed here but deliberately not deep-validated: the
1498
+ * APIFuse registry builder owns deployment validation and resolves omitted
1499
+ * fields against the runtime deployment profiles. The shape mirrors the
1500
+ * registry's `ProviderDeploymentOverrides` contract; every field is
1501
+ * optional. Note that the deployment `runtime` axis
1502
+ * (`shared`/`dedicated`/`browser`) is distinct from the provider execution
1503
+ * `runtime` (`standard`/`shared`/`browser`).
1504
+ */
1505
+ export interface ProviderDeploymentOverrides {
1506
+ runtime?: "shared" | "dedicated" | "browser";
1507
+ language?: "typescript" | "python";
1508
+ replicas?: number;
1509
+ hpa?: {
1510
+ enabled: boolean;
1511
+ minReplicas?: number;
1512
+ maxReplicas?: number;
1513
+ targetCPUUtilizationPercentage?: number;
1514
+ };
1515
+ resources?: {
1516
+ cpu: string;
1517
+ memory: string;
1518
+ };
1519
+ cache?: {
1520
+ redis?: {
1521
+ enabled: boolean;
1522
+ url?: string;
1523
+ };
1524
+ };
1525
+ network?: {
1526
+ additionalTcpPorts?: number[];
1527
+ };
1528
+ buildContext?: string;
1529
+ }
1450
1530
  export interface ProviderDefinition {
1451
1531
  id: string;
1452
1532
  version: string;
1453
1533
  runtime: "standard" | "shared" | "browser";
1534
+ /**
1535
+ * Optional deployment overrides, passed through verbatim from
1536
+ * `defineProvider({ deployment })`. Validation and profile resolution are
1537
+ * owned by the APIFuse registry builder, not the SDK.
1538
+ */
1539
+ deployment?: ProviderDeploymentOverrides;
1454
1540
  allowedHosts?: string[];
1455
1541
  stealth?: {
1456
1542
  profile: string;
@@ -0,0 +1,30 @@
1
+ export declare const NEEDS_INPUT_STATUS: "needs_input";
2
+ export interface ProviderSelectionOption {
3
+ readonly selection_value: string;
4
+ readonly label: string;
5
+ readonly [extra: string]: unknown;
6
+ }
7
+ export interface ProviderRequiredSelection {
8
+ readonly selection_key: string;
9
+ readonly label: string;
10
+ readonly required: boolean;
11
+ readonly selection_type?: string;
12
+ readonly valid_options: readonly ProviderSelectionOption[];
13
+ readonly [extra: string]: unknown;
14
+ }
15
+ export interface ProviderSelectedOption {
16
+ readonly selection_key: string;
17
+ readonly selection_value: string;
18
+ /** Free-text answer for text-kind selections. */
19
+ readonly text?: string;
20
+ /** Quantity for quantity-kind selections. */
21
+ readonly quantity?: number;
22
+ }
23
+ export interface ProviderNeedsInputPayload {
24
+ readonly status: typeof NEEDS_INPUT_STATUS;
25
+ readonly required_selections: readonly ProviderRequiredSelection[];
26
+ readonly selected_options?: readonly ProviderSelectedOption[];
27
+ /** Provider-specific fresh state token(s), e.g. `reservation_state`. */
28
+ readonly [extra: string]: unknown;
29
+ }
30
+ export declare function isProviderNeedsInputPayload(value: unknown): value is ProviderNeedsInputPayload;
@@ -0,0 +1,66 @@
1
+ // Official cross-provider contract for user-input round-trips.
2
+ //
3
+ // Doctrine (born from the 2026-07-20 CatchTable reserve incident): an
4
+ // operation MUST NOT dead-end on a problem the end user can resolve by
5
+ // choosing among live options. Instead of throwing, the provider returns a
6
+ // SUCCESSFUL payload with `status: "needs_input"` that carries everything a
7
+ // consumer-side agent needs to relay the choice verbatim and retry:
8
+ //
9
+ // - `required_selections`: only the still-pending questions, each with
10
+ // human-readable `label`s and `valid_options` the agent shows the user
11
+ // as-is. The agent never chooses on the user's behalf.
12
+ // - `selected_options`: selections already settled, echoed so the follow-up
13
+ // call keeps them without the agent reconstructing anything.
14
+ // - a fresh provider-specific state token (e.g. `reservation_state`) minted
15
+ // at response time, so the retry never races an expired token.
16
+ //
17
+ // Keeping this success-shaped (instead of error `details`) is deliberate:
18
+ // consumer error-shaping layers routinely strip error metadata, and a model
19
+ // that only sees "error" narrates failure to the user. Complex recovery
20
+ // logic belongs to the system, not the model.
21
+ //
22
+ // Deliberately ABSENT: retry templates, next-action routing, or any other
23
+ // agent choreography. Provider payloads carry upstream-backed data only; how
24
+ // to phrase the ask and shape the retry call is the consumer's contract
25
+ // (apifuse#1030). The retry is fully determined by data: copy the echoed
26
+ // selected_options, add the user's new answers, resend with the fresh state.
27
+ export const NEEDS_INPUT_STATUS = "needs_input";
28
+ function isRecord(value) {
29
+ return typeof value === "object" && value !== null && !Array.isArray(value);
30
+ }
31
+ function isSelectionOption(value) {
32
+ return (isRecord(value) &&
33
+ typeof value.selection_value === "string" &&
34
+ typeof value.label === "string");
35
+ }
36
+ function isRequiredSelection(value) {
37
+ return (isRecord(value) &&
38
+ typeof value.selection_key === "string" &&
39
+ typeof value.label === "string" &&
40
+ typeof value.required === "boolean" &&
41
+ Array.isArray(value.valid_options) &&
42
+ value.valid_options.every(isSelectionOption));
43
+ }
44
+ function isSelectedOption(value) {
45
+ return (isRecord(value) &&
46
+ typeof value.selection_key === "string" &&
47
+ typeof value.selection_value === "string");
48
+ }
49
+ export function isProviderNeedsInputPayload(value) {
50
+ if (!isRecord(value)) {
51
+ return false;
52
+ }
53
+ if (value.status !== NEEDS_INPUT_STATUS ||
54
+ !Array.isArray(value.required_selections) ||
55
+ !value.required_selections.every(isRequiredSelection)) {
56
+ return false;
57
+ }
58
+ // A needs_input with nothing to ask AND nothing settled to echo is a
59
+ // no-op dead end — reject it so providers cannot ship it accidentally.
60
+ if (value.required_selections.length > 0) {
61
+ return true;
62
+ }
63
+ return (Array.isArray(value.selected_options) &&
64
+ value.selected_options.length > 0 &&
65
+ value.selected_options.every(isSelectedOption));
66
+ }
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.2.0-beta.1",
2
+ "version": "2.2.0-beta.11",
3
3
  "name": "@apifuse/provider-sdk",
4
4
  "private": false,
5
5
  "type": "module",
@@ -61,6 +61,11 @@
61
61
  "import": "./dist/server/index.js",
62
62
  "default": "./dist/server/index.js"
63
63
  },
64
+ "./stateful": {
65
+ "types": "./dist/stateful/index.d.ts",
66
+ "import": "./dist/stateful/index.js",
67
+ "default": "./dist/stateful/index.js"
68
+ },
64
69
  "./testing": {
65
70
  "types": "./dist/testing/index.d.ts",
66
71
  "import": "./dist/testing/index.js",
@@ -75,24 +80,28 @@
75
80
  "scripts": {
76
81
  "lint": "biome lint .",
77
82
  "lint:fix": "biome lint --write",
83
+ "lint:deprecated": "bun run scripts/lint-deprecated-usage.ts",
78
84
  "format": "biome format --write",
79
- "type-check": "tsgo --noEmit",
85
+ "type-check": "tsc --noEmit",
80
86
  "test": "bun test",
81
- "check": "bun run lint && bun run type-check && bun run build",
87
+ "check": "bun run lint && bun run type-check && bun run lint:deprecated && bun run build",
82
88
  "pack:check": "bun run build && bun bin/apifuse-pack-check.ts",
83
89
  "pack:smoke": "bun run build && bun bin/apifuse-pack-smoke.ts",
90
+ "pack:types": "bun run build && bun bin/apifuse-pack-types.ts",
84
91
  "release:guard": "bun scripts/guard-release-pr.ts",
85
92
  "format:check": "biome format .",
86
- "build": "tsgo -p tsconfig.build.json && rm -rf dist/cli/templates && cp -R src/cli/templates dist/cli/templates && rm -rf dist/auth-turn/fixtures && cp -R src/auth-turn/fixtures dist/auth-turn/fixtures && cp src/auth-turn/auth-turn.v1.schema.json dist/auth-turn/auth-turn.v1.schema.json"
93
+ "build": "tsc -p tsconfig.build.json && rm -rf dist/cli/templates && cp -R src/cli/templates dist/cli/templates && rm -rf dist/auth-turn/fixtures && cp -R src/auth-turn/fixtures dist/auth-turn/fixtures && cp src/auth-turn/auth-turn.v1.schema.json dist/auth-turn/auth-turn.v1.schema.json"
87
94
  },
88
95
  "devDependencies": {
96
+ "@arethetypeswrong/cli": "^0.18.5",
89
97
  "@biomejs/biome": "^2.5.0",
90
98
  "@types/bun": "latest",
91
99
  "@types/node": "^25.9.3",
92
- "@typescript/native-preview": "7.0.0-dev.20260419.1"
100
+ "typescript": "6.0.3"
93
101
  },
94
102
  "dependencies": {
95
103
  "@clack/prompts": "^1.5.1",
104
+ "@rgrove/parse-xml": "4.2.2",
96
105
  "@types/ms": "^2.1.0",
97
106
  "acorn": "^8.17.0",
98
107
  "ajv": "^8.17",
@@ -1,4 +1,4 @@
1
- import type { AuthTurn } from "../types";
1
+ import type { AuthTurn } from "../types.js";
2
2
 
3
3
  export type { AuthTurn };
4
4