@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
@@ -1,28 +1,23 @@
1
1
  import { describe, expect, it } from "bun:test";
2
2
 
3
- import { createProviderCache } from "../runtime/cache";
4
- import { createTestProviderChoiceContext } from "../runtime/choice";
5
- import { createMemoryProviderRuntimeState } from "../runtime/state";
6
- import { createUnsupportedSttClient } from "../runtime/stt";
7
- import { safeParseSchemaSync } from "../schema";
3
+ import { createProviderCache } from "../runtime/cache.js";
4
+ import { createTestProviderChoiceContext } from "../runtime/choice.js";
5
+ import { createMemoryProviderRuntimeState } from "../runtime/state.js";
6
+ import { createUnsupportedSttClient } from "../runtime/stt.js";
7
+ import { safeParseSchemaSync } from "../schema.js";
8
8
  import type {
9
9
  AuthMode,
10
10
  CredentialContext,
11
11
  HttpResponse,
12
12
  ProviderContext,
13
13
  ProviderDefinition,
14
- } from "../types";
14
+ } from "../types.js";
15
15
 
16
16
  // Mirrors CONNECTOR_ID_REGEX in ../define.ts, which defineProvider() enforces.
17
17
  // A single lowercase segment (no hyphen) is a valid id, so the trailing group
18
18
  // is optional (`*`), matching providers like `kakaomap`, `kstartup`, `triple`.
19
19
  const CONNECTOR_ID_REGEX = /^[a-z][a-z0-9]*(-[a-z][a-z0-9]*)*$/;
20
- const VALID_AUTH_MODES = [
21
- "none",
22
- "platform-managed",
23
- "credentials",
24
- "oauth2",
25
- ] as const;
20
+ const VALID_AUTH_MODES = ["none", "platform-managed", "credentials", "oauth2"] as const;
26
21
  const UPDATE_SNAPSHOT_ARGS = new Set(["-u", "--update-snapshots"]);
27
22
 
28
23
  export interface StandardTestsManifest {
@@ -118,9 +113,7 @@ function inferFixtureDir(providerId: string): string {
118
113
  .find((file) => file !== undefined);
119
114
 
120
115
  if (testFile) {
121
- const pathname = testFile.startsWith("file://")
122
- ? new URL(testFile).pathname
123
- : testFile;
116
+ const pathname = testFile.startsWith("file://") ? new URL(testFile).pathname : testFile;
124
117
  return `${pathname.replace(/\/[^/]+$/, "")}/../__fixtures__`;
125
118
  }
126
119
 
@@ -138,10 +131,7 @@ function jsonResponse(data: unknown): HttpResponse {
138
131
  json: async <_T = unknown>() => JSON.parse(JSON.stringify(data)),
139
132
  text: async () => body,
140
133
  arrayBuffer: async () =>
141
- bodyBytes.buffer.slice(
142
- bodyBytes.byteOffset,
143
- bodyBytes.byteOffset + bodyBytes.byteLength,
144
- ),
134
+ bodyBytes.buffer.slice(bodyBytes.byteOffset, bodyBytes.byteOffset + bodyBytes.byteLength),
145
135
  bytes: async () => bodyBytes.slice(0),
146
136
  };
147
137
  }
@@ -184,16 +174,14 @@ function createSnapshotContext(rawFixture: unknown): ProviderContext {
184
174
  engine: "playwright-stealth",
185
175
  newPage: async () => unsupported("ctx.browser.newPage"),
186
176
  rawPage: async () => unsupported("ctx.browser.rawPage"),
187
- withIsolatedContext: async () =>
188
- unsupported("ctx.browser.withIsolatedContext"),
177
+ withIsolatedContext: async () => unsupported("ctx.browser.withIsolatedContext"),
189
178
  solveChallenge: async () => unsupported("ctx.browser.solveChallenge"),
190
179
  },
191
180
  trace: {
192
181
  span: async (_name, fn) => fn(),
193
182
  },
194
183
  auth: {
195
- requestField: async (name) =>
196
- unsupported(`ctx.auth.requestField(${name})`),
184
+ requestField: async (name) => unsupported(`ctx.auth.requestField(${name})`),
197
185
  },
198
186
  stt: createUnsupportedSttClient(
199
187
  "Standard test snapshot context does not support ctx.stt.transcribe",
@@ -292,11 +280,7 @@ function parseSchemaFixture(
292
280
  operationName,
293
281
  fieldName,
294
282
  fixture,
295
- safeParseSchemaSync(
296
- schema,
297
- fixture,
298
- `operations.${operationName}.fixtures.${fieldName}`,
299
- ),
283
+ safeParseSchemaSync(schema, fixture, `operations.${operationName}.fixtures.${fieldName}`),
300
284
  );
301
285
  }
302
286
 
@@ -322,40 +306,20 @@ export function runStandardTests(
322
306
 
323
307
  for (const [operationName, op] of operations) {
324
308
  if (op.fixtures?.request !== undefined) {
325
- parseSchemaFixture(
326
- operationName,
327
- "request",
328
- op.input,
329
- op.fixtures.request,
330
- );
309
+ parseSchemaFixture(operationName, "request", op.input, op.fixtures.request);
331
310
  }
332
311
 
333
312
  if (op.fixtures?.response !== undefined) {
334
- parseSchemaFixture(
335
- operationName,
336
- "response",
337
- op.output,
338
- op.fixtures.response,
339
- );
313
+ parseSchemaFixture(operationName, "response", op.output, op.fixtures.response);
340
314
  }
341
315
 
342
316
  if (isFixtureEnvelope(rawFixture)) {
343
317
  if (rawFixture.request !== undefined) {
344
- parseSchemaFixture(
345
- operationName,
346
- "request",
347
- op.input,
348
- rawFixture.request,
349
- );
318
+ parseSchemaFixture(operationName, "request", op.input, rawFixture.request);
350
319
  }
351
320
 
352
321
  if (rawFixture.response !== undefined) {
353
- parseSchemaFixture(
354
- operationName,
355
- "response",
356
- op.output,
357
- rawFixture.response,
358
- );
322
+ parseSchemaFixture(operationName, "response", op.output, rawFixture.response);
359
323
  }
360
324
  }
361
325
  }
@@ -411,21 +375,11 @@ export function runStandardTests(
411
375
  it("operation schemas can parse fixture data", () => {
412
376
  for (const [operationName, op] of operations) {
413
377
  if (op.fixtures?.request !== undefined && op.input) {
414
- parseSchemaFixture(
415
- operationName,
416
- "request",
417
- op.input,
418
- op.fixtures.request,
419
- );
378
+ parseSchemaFixture(operationName, "request", op.input, op.fixtures.request);
420
379
  }
421
380
 
422
381
  if (op.fixtures?.response !== undefined && op.output) {
423
- parseSchemaFixture(
424
- operationName,
425
- "response",
426
- op.output,
427
- op.fixtures.response,
428
- );
382
+ parseSchemaFixture(operationName, "response", op.output, op.fixtures.response);
429
383
  }
430
384
 
431
385
  expect(operationName).toBeTruthy();
@@ -471,9 +425,7 @@ export function runStandardTests(
471
425
  await Bun.write(snapshotPath, serialized);
472
426
  }
473
427
 
474
- const expected: unknown = JSON.parse(
475
- await Bun.file(snapshotPath).text(),
476
- );
428
+ const expected: unknown = JSON.parse(await Bun.file(snapshotPath).text());
477
429
  expect(actual).toEqual(expected);
478
430
  });
479
431
  }
package/src/types.ts CHANGED
@@ -769,7 +769,25 @@ export type ProviderAccessVisibility = "public" | "early_access";
769
769
 
770
770
  export type ProviderProxyMode = "disabled" | "optional" | "required";
771
771
 
772
- export type ProviderProxyProvider = "smartproxy" | "decodo" | "custom";
772
+ /**
773
+ * Proxy egress vendors. These are FOUR DISTINCT services — do not conflate them
774
+ * (a common mistake because the names collide with a well-known rebrand):
775
+ *
776
+ * - `smartproxy` — **api.smartproxy.org**, a residential proxy with an IP
777
+ * *extraction/allocation* API (app_key → a pool of raw `ip:port` CONNECT
778
+ * endpoints). This is our own vendor. It is NOT the company formerly named
779
+ * "Smartproxy". Credentials: `APIFUSE__PROXY__SMARTPROXY_APP_KEY`.
780
+ * - `nodemaven` — **gate.nodemaven.com**, a *gateway* proxy with static
781
+ * credentials; geo/session encoded in the username, no allocation API.
782
+ * - `decodo` — **decodo.com**, the *gateway* proxy that was named "Smartproxy"
783
+ * (smartproxy.com) before its 2025 rebrand to Decodo. Sticky sessions via
784
+ * username params. A different company from `smartproxy` above.
785
+ * **@deprecated** — unused; no managed adapter. Use `smartproxy`/`nodemaven`,
786
+ * or the `APIFUSE__PROXY__URL` bring-your-own escape hatch.
787
+ * - `custom` — **@deprecated** bring-your-own static proxy URL marker. The
788
+ * `APIFUSE__PROXY__URL` env still works without declaring this value.
789
+ */
790
+ export type ProviderProxyProvider = "smartproxy" | "nodemaven" | "decodo" | "custom";
773
791
 
774
792
  export type ProviderProxySessionAffinity =
775
793
  | "request"
@@ -783,7 +801,18 @@ export interface ProviderProxyPolicy {
783
801
  * certificate verification, and vendor allocator endpoints are SDK-owned.
784
802
  */
785
803
  mode: ProviderProxyMode;
804
+ /**
805
+ * @deprecated Use `providers: [...]` to declare an ordered vendor fallback
806
+ * chain. A single-element `providers` list is equivalent to this field.
807
+ */
786
808
  provider?: ProviderProxyProvider;
809
+ /**
810
+ * Ordered proxy-vendor fallback chain. The SDK tries each vendor in order and
811
+ * fails over to the next when a vendor lacks credentials or its allocation /
812
+ * transport is exhausted. When omitted, `provider` (or the platform default)
813
+ * is used as a single-vendor chain.
814
+ */
815
+ providers?: ProviderProxyProvider[];
787
816
  geo?: {
788
817
  /** ISO 3166-1 alpha-2 country code, for example KR or US. */
789
818
  country?: Iso3166Alpha2CountryCode;
@@ -1759,6 +1788,19 @@ export interface OperationDefinition<
1759
1788
  TInput extends SchemaLike = SchemaLike,
1760
1789
  TOutput extends SchemaLike = SchemaLike,
1761
1790
  > {
1791
+ /**
1792
+ * Short English display title for the operation. The SDK passes it through
1793
+ * verbatim; the APIFuse registry derives the operation's en locale title
1794
+ * baseline from it (`docs.titleKey` remains available as an explicit key
1795
+ * override).
1796
+ */
1797
+ title?: string;
1798
+ /**
1799
+ * Raw English operation description. The SDK passes it through verbatim;
1800
+ * keyed descriptions via `descriptionKey` remain the primary flow, and
1801
+ * provider lint rules for raw prose descriptions still apply.
1802
+ */
1803
+ description?: string;
1762
1804
  descriptionKey?: ProviderLocaleKeyInput;
1763
1805
  docs?: OperationDocMeta;
1764
1806
  whenToUseKeys?: readonly ProviderLocaleKeyInput[];
@@ -1797,10 +1839,55 @@ export interface OperationDefinition<
1797
1839
  healthCheckUnsupported?: HealthCheckUnsupported;
1798
1840
  }
1799
1841
 
1842
+ /**
1843
+ * Author-declared deployment overrides accepted as the optional top-level
1844
+ * `deployment` key on `defineProvider()`.
1845
+ *
1846
+ * The SDK passes this object through VERBATIM onto the returned provider
1847
+ * definition — it is typed here but deliberately not deep-validated: the
1848
+ * APIFuse registry builder owns deployment validation and resolves omitted
1849
+ * fields against the runtime deployment profiles. The shape mirrors the
1850
+ * registry's `ProviderDeploymentOverrides` contract; every field is
1851
+ * optional. Note that the deployment `runtime` axis
1852
+ * (`shared`/`dedicated`/`browser`) is distinct from the provider execution
1853
+ * `runtime` (`standard`/`shared`/`browser`).
1854
+ */
1855
+ export interface ProviderDeploymentOverrides {
1856
+ runtime?: "shared" | "dedicated" | "browser";
1857
+ language?: "typescript" | "python";
1858
+ replicas?: number;
1859
+ hpa?: {
1860
+ enabled: boolean;
1861
+ minReplicas?: number;
1862
+ maxReplicas?: number;
1863
+ targetCPUUtilizationPercentage?: number;
1864
+ };
1865
+ resources?: {
1866
+ cpu: string;
1867
+ memory: string;
1868
+ };
1869
+ cache?: {
1870
+ redis?: {
1871
+ enabled: boolean;
1872
+ url?: string;
1873
+ };
1874
+ };
1875
+ network?: {
1876
+ additionalTcpPorts?: number[];
1877
+ };
1878
+ buildContext?: string;
1879
+ }
1880
+
1800
1881
  export interface ProviderDefinition {
1801
1882
  id: string;
1802
1883
  version: string;
1803
1884
  runtime: "standard" | "shared" | "browser";
1885
+ /**
1886
+ * Optional deployment overrides, passed through verbatim from
1887
+ * `defineProvider({ deployment })`. Validation and profile resolution are
1888
+ * owned by the APIFuse registry builder, not the SDK.
1889
+ */
1890
+ deployment?: ProviderDeploymentOverrides;
1804
1891
  allowedHosts?: string[];
1805
1892
  stealth?: {
1806
1893
  profile: string;
@@ -0,0 +1,118 @@
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
+
28
+ export const NEEDS_INPUT_STATUS = "needs_input" as const;
29
+
30
+ export interface ProviderSelectionOption {
31
+ readonly selection_value: string;
32
+ readonly label: string;
33
+ readonly [extra: string]: unknown;
34
+ }
35
+
36
+ export interface ProviderRequiredSelection {
37
+ readonly selection_key: string;
38
+ readonly label: string;
39
+ readonly required: boolean;
40
+ readonly selection_type?: string;
41
+ readonly valid_options: readonly ProviderSelectionOption[];
42
+ readonly [extra: string]: unknown;
43
+ }
44
+
45
+ export interface ProviderSelectedOption {
46
+ readonly selection_key: string;
47
+ readonly selection_value: string;
48
+ /** Free-text answer for text-kind selections. */
49
+ readonly text?: string;
50
+ /** Quantity for quantity-kind selections. */
51
+ readonly quantity?: number;
52
+ }
53
+
54
+ export interface ProviderNeedsInputPayload {
55
+ readonly status: typeof NEEDS_INPUT_STATUS;
56
+ readonly required_selections: readonly ProviderRequiredSelection[];
57
+ readonly selected_options?: readonly ProviderSelectedOption[];
58
+ /** Provider-specific fresh state token(s), e.g. `reservation_state`. */
59
+ readonly [extra: string]: unknown;
60
+ }
61
+
62
+ function isRecord(value: unknown): value is Record<string, unknown> {
63
+ return typeof value === "object" && value !== null && !Array.isArray(value);
64
+ }
65
+
66
+ function isSelectionOption(value: unknown): value is ProviderSelectionOption {
67
+ return (
68
+ isRecord(value) &&
69
+ typeof value.selection_value === "string" &&
70
+ typeof value.label === "string"
71
+ );
72
+ }
73
+
74
+ function isRequiredSelection(
75
+ value: unknown,
76
+ ): value is ProviderRequiredSelection {
77
+ return (
78
+ isRecord(value) &&
79
+ typeof value.selection_key === "string" &&
80
+ typeof value.label === "string" &&
81
+ typeof value.required === "boolean" &&
82
+ Array.isArray(value.valid_options) &&
83
+ value.valid_options.every(isSelectionOption)
84
+ );
85
+ }
86
+
87
+ function isSelectedOption(value: unknown): value is ProviderSelectedOption {
88
+ return (
89
+ isRecord(value) &&
90
+ typeof value.selection_key === "string" &&
91
+ typeof value.selection_value === "string"
92
+ );
93
+ }
94
+
95
+ export function isProviderNeedsInputPayload(
96
+ value: unknown,
97
+ ): value is ProviderNeedsInputPayload {
98
+ if (!isRecord(value)) {
99
+ return false;
100
+ }
101
+ if (
102
+ value.status !== NEEDS_INPUT_STATUS ||
103
+ !Array.isArray(value.required_selections) ||
104
+ !value.required_selections.every(isRequiredSelection)
105
+ ) {
106
+ return false;
107
+ }
108
+ // A needs_input with nothing to ask AND nothing settled to echo is a
109
+ // no-op dead end — reject it so providers cannot ship it accidentally.
110
+ if (value.required_selections.length > 0) {
111
+ return true;
112
+ }
113
+ return (
114
+ Array.isArray(value.selected_options) &&
115
+ value.selected_options.length > 0 &&
116
+ value.selected_options.every(isSelectedOption)
117
+ );
118
+ }
@@ -1 +0,0 @@
1
- @AGENTS.md
@@ -1 +0,0 @@
1
- @AGENTS.md