@apifuse/provider-sdk 2.2.0-beta.2 → 2.2.0-beta.21

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 (291) hide show
  1. package/AUTHORING.md +487 -0
  2. package/CHANGELOG.md +90 -0
  3. package/README.md +49 -3
  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 +36 -81
  10. package/bin/apifuse-pack-types.ts +305 -0
  11. package/bin/apifuse-perf.ts +45 -127
  12. package/bin/apifuse-record.ts +659 -111
  13. package/bin/apifuse-submit-check.ts +546 -48
  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 +9 -1
  23. package/dist/ceremonies/index.js +65 -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 +176 -8
  32. package/dist/config/loader.js +424 -95
  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 +9 -1
  39. package/dist/define.js +304 -119
  40. package/dist/dev.d.ts +1 -1
  41. package/dist/dev.js +1 -1
  42. package/dist/error-resolution.d.ts +2 -0
  43. package/dist/error-resolution.js +90 -0
  44. package/dist/errors.d.ts +22 -1
  45. package/dist/errors.js +88 -0
  46. package/dist/fixture-sanitization.d.ts +26 -0
  47. package/dist/fixture-sanitization.js +216 -0
  48. package/dist/i18n/catalog.d.ts +2 -2
  49. package/dist/i18n/catalog.js +4 -10
  50. package/dist/i18n/index.d.ts +2 -2
  51. package/dist/i18n/index.js +2 -2
  52. package/dist/i18n/keys.d.ts +2 -2
  53. package/dist/index.d.ts +46 -42
  54. package/dist/index.js +41 -37
  55. package/dist/lint.d.ts +1 -1
  56. package/dist/lint.js +8 -15
  57. package/dist/native-address.d.ts +43 -0
  58. package/dist/native-address.js +281 -0
  59. package/dist/native-egress-policy.d.ts +31 -0
  60. package/dist/native-egress-policy.js +288 -0
  61. package/dist/observability.d.ts +5 -2
  62. package/dist/observability.js +48 -1
  63. package/dist/provider.d.ts +12 -11
  64. package/dist/provider.js +10 -9
  65. package/dist/public-schema-field-lint.d.ts +1 -1
  66. package/dist/recipes/gov-api.js +1 -1
  67. package/dist/runtime/auth-flow.d.ts +2 -1
  68. package/dist/runtime/auth-flow.js +4 -3
  69. package/dist/runtime/browser.d.ts +1 -1
  70. package/dist/runtime/browser.js +15 -29
  71. package/dist/runtime/cache.d.ts +1 -1
  72. package/dist/runtime/cache.js +4 -8
  73. package/dist/runtime/choice.d.ts +1 -1
  74. package/dist/runtime/choice.js +31 -35
  75. package/dist/runtime/credential.d.ts +1 -1
  76. package/dist/runtime/credential.js +1 -1
  77. package/dist/runtime/env.d.ts +1 -1
  78. package/dist/runtime/executor.d.ts +1 -1
  79. package/dist/runtime/executor.js +31 -4
  80. package/dist/runtime/http.d.ts +2 -2
  81. package/dist/runtime/http.js +387 -47
  82. package/dist/runtime/insights.d.ts +1 -1
  83. package/dist/runtime/insights.js +6 -13
  84. package/dist/runtime/instrumentation.d.ts +2 -2
  85. package/dist/runtime/instrumentation.js +345 -22
  86. package/dist/runtime/keyring.js +1 -1
  87. package/dist/runtime/namespace.js +1 -1
  88. package/dist/runtime/native-network.d.ts +127 -0
  89. package/dist/runtime/native-network.js +1298 -0
  90. package/dist/runtime/otlp.d.ts +1 -1
  91. package/dist/runtime/perf.d.ts +1 -1
  92. package/dist/runtime/provider.d.ts +1 -1
  93. package/dist/runtime/provider.js +1 -2
  94. package/dist/runtime/proxy-errors.d.ts +1 -1
  95. package/dist/runtime/proxy-errors.js +9 -7
  96. package/dist/runtime/proxy-nodemaven.d.ts +56 -0
  97. package/dist/runtime/proxy-nodemaven.js +146 -0
  98. package/dist/runtime/proxy-retry-policy.d.ts +2 -2
  99. package/dist/runtime/proxy-retry-policy.js +2 -2
  100. package/dist/runtime/proxy-telemetry.d.ts +2 -1
  101. package/dist/runtime/proxy-telemetry.js +55 -52
  102. package/dist/runtime/redirects.d.ts +29 -0
  103. package/dist/runtime/redirects.js +36 -0
  104. package/dist/runtime/redis.d.ts +1 -1
  105. package/dist/runtime/redis.js +2 -4
  106. package/dist/runtime/request-options.d.ts +68 -1
  107. package/dist/runtime/request-options.js +548 -0
  108. package/dist/runtime/secrets.d.ts +27 -0
  109. package/dist/runtime/secrets.js +51 -0
  110. package/dist/runtime/state.d.ts +2 -2
  111. package/dist/runtime/state.js +238 -26
  112. package/dist/runtime/stealth.d.ts +5 -3
  113. package/dist/runtime/stealth.js +423 -143
  114. package/dist/runtime/stt.d.ts +1 -1
  115. package/dist/runtime/stt.js +11 -15
  116. package/dist/runtime/trace.d.ts +2 -2
  117. package/dist/runtime/trace.js +2 -4
  118. package/dist/runtime/waterfall.d.ts +1 -1
  119. package/dist/schema.d.ts +1 -1
  120. package/dist/schema.js +7 -15
  121. package/dist/serve.d.ts +1 -1
  122. package/dist/serve.js +1 -1
  123. package/dist/server/index.d.ts +7 -7
  124. package/dist/server/index.js +6 -6
  125. package/dist/server/self-test-input-tokens.d.ts +2 -1
  126. package/dist/server/self-test-input-tokens.js +18 -14
  127. package/dist/server/self-test-redaction.d.ts +1 -1
  128. package/dist/server/self-test-redaction.js +1 -1
  129. package/dist/server/self-test.d.ts +104 -3
  130. package/dist/server/self-test.js +673 -115
  131. package/dist/server/serve.d.ts +116 -4
  132. package/dist/server/serve.js +799 -128
  133. package/dist/server/types.d.ts +34 -9
  134. package/dist/server/types.js +8 -1
  135. package/dist/stateful/errors.d.ts +14 -0
  136. package/dist/stateful/errors.js +14 -0
  137. package/dist/stateful/http-provider-event-emitter.d.ts +40 -0
  138. package/dist/stateful/http-provider-event-emitter.js +237 -0
  139. package/dist/stateful/http-session-owner-registry.d.ts +44 -0
  140. package/dist/stateful/http-session-owner-registry.js +210 -0
  141. package/dist/stateful/index.d.ts +18 -0
  142. package/dist/stateful/index.js +18 -0
  143. package/dist/stateful/provider-event-delivery-failures.d.ts +32 -0
  144. package/dist/stateful/provider-event-delivery-failures.js +43 -0
  145. package/dist/stateful/provider-event-pipeline-metrics.d.ts +46 -0
  146. package/dist/stateful/provider-event-pipeline-metrics.js +48 -0
  147. package/dist/stateful/provider-event-pipeline.d.ts +50 -0
  148. package/dist/stateful/provider-event-pipeline.js +1 -0
  149. package/dist/stateful/provider-events.d.ts +101 -0
  150. package/dist/stateful/provider-events.js +289 -0
  151. package/dist/stateful/session-key.d.ts +15 -0
  152. package/dist/stateful/session-key.js +86 -0
  153. package/dist/stateful/stateful-provider-adapter-context.d.ts +5 -0
  154. package/dist/stateful/stateful-provider-adapter-context.js +42 -0
  155. package/dist/stateful/stateful-provider-adapter-metrics.d.ts +15 -0
  156. package/dist/stateful/stateful-provider-adapter-metrics.js +21 -0
  157. package/dist/stateful/stateful-provider-adapter.d.ts +98 -0
  158. package/dist/stateful/stateful-provider-adapter.js +287 -0
  159. package/dist/stateful/stateful-provider-observability.d.ts +62 -0
  160. package/dist/stateful/stateful-provider-observability.js +161 -0
  161. package/dist/stateful/stateful-provider-owner-forwarder.d.ts +41 -0
  162. package/dist/stateful/stateful-provider-owner-forwarder.js +215 -0
  163. package/dist/stateful/stateful-provider-runtime-context.d.ts +32 -0
  164. package/dist/stateful/stateful-provider-runtime-context.js +60 -0
  165. package/dist/stateful/stateful-provider-runtime-executor.d.ts +34 -0
  166. package/dist/stateful/stateful-provider-runtime-executor.js +52 -0
  167. package/dist/stateful/stateful-provider-session-routing.d.ts +71 -0
  168. package/dist/stateful/stateful-provider-session-routing.js +353 -0
  169. package/dist/stateful/stateful-provider-session-runtime.d.ts +98 -0
  170. package/dist/stateful/stateful-provider-session-runtime.js +245 -0
  171. package/dist/stateful-signing.d.ts +18 -0
  172. package/dist/stateful-signing.js +27 -0
  173. package/dist/stealth/profiles.d.ts +1 -1
  174. package/dist/stealth/profiles.js +5 -14
  175. package/dist/stream-evidence.d.ts +74 -0
  176. package/dist/stream-evidence.js +785 -0
  177. package/dist/stream.d.ts +1 -1
  178. package/dist/testing/index.d.ts +2 -2
  179. package/dist/testing/index.js +2 -2
  180. package/dist/testing/run.d.ts +32 -2
  181. package/dist/testing/run.js +478 -28
  182. package/dist/types.d.ts +342 -14
  183. package/dist/types.js +1 -0
  184. package/dist/user-input.d.ts +30 -0
  185. package/dist/user-input.js +66 -0
  186. package/package.json +16 -5
  187. package/src/auth-turn/index.ts +1 -1
  188. package/src/auth.ts +28 -86
  189. package/src/ceremonies/index.ts +103 -78
  190. package/src/cli/commands.ts +10 -0
  191. package/src/cli/create.ts +42 -35
  192. package/src/cli/prompt-assets.ts +865 -0
  193. package/src/cli/templates/provider/AGENTS.md.tpl +17 -8
  194. package/src/config/loader.ts +652 -204
  195. package/src/contract-serialization.ts +5 -11
  196. package/src/contract-types.ts +2 -2
  197. package/src/contract.ts +12 -28
  198. package/src/define.ts +499 -498
  199. package/src/dev.ts +4 -9
  200. package/src/error-resolution.ts +91 -0
  201. package/src/errors.ts +110 -5
  202. package/src/fixture-sanitization.ts +247 -0
  203. package/src/i18n/catalog.ts +10 -32
  204. package/src/i18n/index.ts +2 -2
  205. package/src/i18n/keys.ts +5 -11
  206. package/src/index.ts +112 -42
  207. package/src/lint.ts +88 -152
  208. package/src/native-address.ts +340 -0
  209. package/src/native-egress-policy.ts +358 -0
  210. package/src/observability.ts +51 -1
  211. package/src/provider.ts +66 -11
  212. package/src/public-schema-field-lint.ts +7 -33
  213. package/src/recipes/gov-api.ts +2 -5
  214. package/src/runtime/auth-flow.ts +7 -7
  215. package/src/runtime/browser.ts +64 -187
  216. package/src/runtime/cache.ts +20 -67
  217. package/src/runtime/choice.ts +79 -132
  218. package/src/runtime/credential.ts +2 -2
  219. package/src/runtime/env.ts +1 -1
  220. package/src/runtime/executor.ts +43 -20
  221. package/src/runtime/http.ts +494 -57
  222. package/src/runtime/insights.ts +15 -53
  223. package/src/runtime/instrumentation.ts +495 -66
  224. package/src/runtime/keyring.ts +7 -19
  225. package/src/runtime/namespace.ts +2 -7
  226. package/src/runtime/native-network.ts +1686 -0
  227. package/src/runtime/otlp.ts +12 -23
  228. package/src/runtime/perf.ts +1 -1
  229. package/src/runtime/provider.ts +4 -9
  230. package/src/runtime/proxy-errors.ts +29 -42
  231. package/src/runtime/proxy-nodemaven.ts +221 -0
  232. package/src/runtime/proxy-retry-policy.ts +3 -3
  233. package/src/runtime/proxy-telemetry.ts +79 -77
  234. package/src/runtime/redirects.ts +66 -0
  235. package/src/runtime/redis.ts +4 -12
  236. package/src/runtime/request-options.ts +679 -9
  237. package/src/runtime/secrets.ts +64 -0
  238. package/src/runtime/state.ts +353 -133
  239. package/src/runtime/stealth.ts +505 -154
  240. package/src/runtime/stt.ts +38 -94
  241. package/src/runtime/trace.ts +14 -44
  242. package/src/runtime/waterfall.ts +5 -18
  243. package/src/schema.ts +23 -84
  244. package/src/serve.ts +1 -1
  245. package/src/server/index.ts +29 -7
  246. package/src/server/self-test-input-tokens.ts +29 -14
  247. package/src/server/self-test-redaction.ts +2 -2
  248. package/src/server/self-test.ts +857 -132
  249. package/src/server/serve.ts +1151 -328
  250. package/src/server/types.ts +12 -13
  251. package/src/stateful/README.md +146 -0
  252. package/src/stateful/errors.ts +23 -0
  253. package/src/stateful/http-provider-event-emitter.ts +314 -0
  254. package/src/stateful/http-session-owner-registry.ts +306 -0
  255. package/src/stateful/index.ts +18 -0
  256. package/src/stateful/provider-event-delivery-failures.ts +80 -0
  257. package/src/stateful/provider-event-pipeline-metrics.ts +95 -0
  258. package/src/stateful/provider-event-pipeline.ts +61 -0
  259. package/src/stateful/provider-events.ts +462 -0
  260. package/src/stateful/session-key.ts +111 -0
  261. package/src/stateful/stateful-provider-adapter-context.ts +59 -0
  262. package/src/stateful/stateful-provider-adapter-metrics.ts +48 -0
  263. package/src/stateful/stateful-provider-adapter.ts +562 -0
  264. package/src/stateful/stateful-provider-observability.ts +261 -0
  265. package/src/stateful/stateful-provider-owner-forwarder.ts +287 -0
  266. package/src/stateful/stateful-provider-runtime-context.ts +92 -0
  267. package/src/stateful/stateful-provider-runtime-executor.ts +96 -0
  268. package/src/stateful/stateful-provider-session-routing.ts +555 -0
  269. package/src/stateful/stateful-provider-session-runtime.ts +403 -0
  270. package/src/stateful-signing.ts +46 -0
  271. package/src/stealth/profiles.ts +10 -26
  272. package/src/stream-evidence.ts +988 -0
  273. package/src/stream.ts +8 -19
  274. package/src/testing/index.ts +10 -2
  275. package/src/testing/run.ts +653 -74
  276. package/src/types.ts +408 -28
  277. package/src/user-input.ts +118 -0
  278. package/dist/cli/templates/provider/CLAUDE.md.tpl +0 -1
  279. package/src/cli/templates/provider/CLAUDE.md.tpl +0 -1
  280. /package/dist/cli/templates/provider/{skills → .agents/skills}/fixtures-and-recording/SKILL.md.tpl +0 -0
  281. /package/dist/cli/templates/provider/{skills → .agents/skills}/health-checks-and-fail-closed/SKILL.md.tpl +0 -0
  282. /package/dist/cli/templates/provider/{skills → .agents/skills}/normalization-standards/SKILL.md.tpl +0 -0
  283. /package/dist/cli/templates/provider/{skills → .agents/skills}/pagination-and-counts/SKILL.md.tpl +0 -0
  284. /package/dist/cli/templates/provider/{skills → .agents/skills}/upstream-contract-verification/SKILL.md.tpl +0 -0
  285. /package/dist/cli/templates/provider/{skills → .agents/skills}/upstream-notes/README.md.tpl +0 -0
  286. /package/src/cli/templates/provider/{skills → .agents/skills}/fixtures-and-recording/SKILL.md.tpl +0 -0
  287. /package/src/cli/templates/provider/{skills → .agents/skills}/health-checks-and-fail-closed/SKILL.md.tpl +0 -0
  288. /package/src/cli/templates/provider/{skills → .agents/skills}/normalization-standards/SKILL.md.tpl +0 -0
  289. /package/src/cli/templates/provider/{skills → .agents/skills}/pagination-and-counts/SKILL.md.tpl +0 -0
  290. /package/src/cli/templates/provider/{skills → .agents/skills}/upstream-contract-verification/SKILL.md.tpl +0 -0
  291. /package/src/cli/templates/provider/{skills → .agents/skills}/upstream-notes/README.md.tpl +0 -0
package/src/auth.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { AuthError, ProviderError } from "./errors";
1
+ import { AuthError, ProviderError } from "./errors.js";
2
2
  import type {
3
3
  AuthAbortData,
4
4
  AuthConfig,
@@ -10,7 +10,7 @@ import type {
10
10
  CredentialDeclaration,
11
11
  FlowContext,
12
12
  ProviderLocaleKeyInput,
13
- } from "./types";
13
+ } from "./types.js";
14
14
 
15
15
  const CREDENTIALS_AUTH_CHALLENGE_CONTEXT_KEY = "__credentialsAuthChallenge";
16
16
  const DEFAULT_COMPLETE_TURN_ID = "auth.complete";
@@ -33,11 +33,7 @@ function isSensitiveAuthDataKey(key: string): boolean {
33
33
  return SENSITIVE_ABORT_DATA_KEY_PATTERN.test(normalizedAuthDataKey(key));
34
34
  }
35
35
 
36
- export type CredentialsAuthFieldType =
37
- | "string"
38
- | "email"
39
- | "password"
40
- | "otp";
36
+ export type CredentialsAuthFieldType = "string" | "email" | "password" | "otp";
41
37
 
42
38
  export interface CredentialsAuthField {
43
39
  type?: CredentialsAuthFieldType;
@@ -138,10 +134,9 @@ function abortData(options: {
138
134
  };
139
135
  }
140
136
 
141
- export function createAuthFlowHelpers(options: {
142
- readonly signal?: AbortSignal;
143
- readonly deadline?: string;
144
- } = {}): AuthFlowTerminalContext {
137
+ export function createAuthFlowHelpers(
138
+ options: { readonly signal?: AbortSignal; readonly deadline?: string } = {},
139
+ ): AuthFlowTerminalContext {
145
140
  return {
146
141
  ...(options.signal ? { signal: options.signal } : {}),
147
142
  ...(options.deadline ? { deadline: options.deadline } : {}),
@@ -156,16 +151,7 @@ export function createAuthFlowHelpers(options: {
156
151
  },
157
152
  };
158
153
  },
159
- abort({
160
- code,
161
- message,
162
- retry,
163
- actionHint,
164
- fieldErrors,
165
- data,
166
- turnId,
167
- expiresAt,
168
- }) {
154
+ abort({ code, message, retry, actionHint, fieldErrors, data, turnId, expiresAt }) {
169
155
  return {
170
156
  kind: "abort",
171
157
  ...authTurnBase({ turnId, defaultTurnId: DEFAULT_ABORT_TURN_ID, expiresAt }),
@@ -190,8 +176,7 @@ export function createAuthFlowHelpers(options: {
190
176
  ...(options.hintKey ? { hintKey: options.hintKey } : {}),
191
177
  ...(options.timing ? { timing: options.timing } : {}),
192
178
  ...(options.data ? { data: options.data } : {}),
193
- expectedInput:
194
- options.expectedInput ?? expectedInputFromFields(options.fields ?? {}),
179
+ expectedInput: options.expectedInput ?? expectedInputFromFields(options.fields ?? {}),
195
180
  };
196
181
  },
197
182
  nextPoll(options = {}) {
@@ -223,9 +208,7 @@ export class AuthAbortError extends AuthError {
223
208
  }
224
209
  }
225
210
 
226
- export interface CredentialsAuthCompleteResult<
227
- TCredentialKeys extends readonly string[],
228
- > {
211
+ export interface CredentialsAuthCompleteResult<TCredentialKeys extends readonly string[]> {
229
212
  credential: CredentialsAuthCredential<TCredentialKeys>;
230
213
  /** Additional non-credential auth-flow data to return alongside credential. */
231
214
  data?: Record<string, unknown>;
@@ -247,9 +230,7 @@ export interface CredentialsAuthChallengeRequest<TChallengeId extends string = s
247
230
  export type CredentialsAuthLoginResult<
248
231
  TCredentialKeys extends readonly string[],
249
232
  TChallengeId extends string = string,
250
- > =
251
- | CredentialsAuthCompleteResult<TCredentialKeys>
252
- | CredentialsAuthChallengeRequest<TChallengeId>;
233
+ > = CredentialsAuthCompleteResult<TCredentialKeys> | CredentialsAuthChallengeRequest<TChallengeId>;
253
234
 
254
235
  export interface CredentialsAuthChallengeDefinition<
255
236
  TFields extends CredentialsAuthFields,
@@ -351,12 +332,8 @@ function expectedInputFromFields(fields: CredentialsAuthFields): Record<string,
351
332
  ...(field.type === "password" ? { format: "password" } : {}),
352
333
  ...(field.type === "otp" ? { format: "otp" } : {}),
353
334
  ...(field.labelKey ? { nameKey: field.labelKey } : {}),
354
- ...(field.descriptionKey
355
- ? { descriptionKey: field.descriptionKey }
356
- : {}),
357
- ...(field.placeholderKey
358
- ? { placeholderKey: field.placeholderKey }
359
- : {}),
335
+ ...(field.descriptionKey ? { descriptionKey: field.descriptionKey } : {}),
336
+ ...(field.placeholderKey ? { placeholderKey: field.placeholderKey } : {}),
360
337
  ...(field.sensitive || field.type === "password" || field.type === "otp"
361
338
  ? { sensitive: true }
362
339
  : {}),
@@ -437,10 +414,7 @@ function getPendingChallenge(ctx: FlowContext): PendingCredentialsAuthChallenge
437
414
  };
438
415
  }
439
416
 
440
- function setPendingChallenge(
441
- ctx: FlowContext,
442
- challenge: PendingCredentialsAuthChallenge,
443
- ): void {
417
+ function setPendingChallenge(ctx: FlowContext, challenge: PendingCredentialsAuthChallenge): void {
444
418
  ctx.context.set(CREDENTIALS_AUTH_CHALLENGE_CONTEXT_KEY, challenge);
445
419
  }
446
420
 
@@ -473,9 +447,7 @@ function retryTurn(
473
447
  turnId: retryTurnId,
474
448
  expectedInput,
475
449
  data: {
476
- fieldErrors: Object.fromEntries(
477
- missing.map((name) => [name, "Required"]),
478
- ),
450
+ fieldErrors: Object.fromEntries(missing.map((name) => [name, "Required"])),
479
451
  fieldErrorKeys: Object.fromEntries(
480
452
  missing.map((name) => [name, "auth.credentials.fieldRequired"]),
481
453
  ),
@@ -499,18 +471,12 @@ function completeTurn<TCredentialKeys extends readonly string[]>(
499
471
  typeof result.credential !== "object" ||
500
472
  Array.isArray(result.credential)
501
473
  ) {
502
- throw new ProviderError(
503
- "Credentials auth login completed without a credential object",
504
- {
505
- code: "credentials_auth_missing_credential",
506
- fix: "Return { credential: { ... } } from defineCredentialsAuth handlers. Gateway persists only auth.flow complete data.credential into the connection.",
507
- },
508
- );
474
+ throw new ProviderError("Credentials auth login completed without a credential object", {
475
+ code: "credentials_auth_missing_credential",
476
+ fix: "Return { credential: { ... } } from defineCredentialsAuth handlers. Gateway persists only auth.flow complete data.credential into the connection.",
477
+ });
509
478
  }
510
- assertCredentialKeys(
511
- credentialKeys,
512
- result.credential as Record<string, unknown>,
513
- );
479
+ assertCredentialKeys(credentialKeys, result.credential as Record<string, unknown>);
514
480
  return {
515
481
  kind: "complete",
516
482
  turnId: result.turnId ?? defaultTurnId,
@@ -523,24 +489,18 @@ function completeTurn<TCredentialKeys extends readonly string[]>(
523
489
  }
524
490
 
525
491
  function challengeTurn(
526
- definition: CredentialsAuthChallengeDefinition<
527
- CredentialsAuthFields,
528
- readonly string[],
529
- string
530
- >,
492
+ definition: CredentialsAuthChallengeDefinition<CredentialsAuthFields, readonly string[], string>,
531
493
  request: CredentialsAuthChallengeRequest<string>,
532
494
  ): AuthTurn {
533
- const expectedInput = definition.fields
534
- ? expectedInputFromFields(definition.fields)
535
- : undefined;
495
+ const expectedInput = definition.fields ? expectedInputFromFields(definition.fields) : undefined;
536
496
  return {
537
497
  kind: expectedInput ? "form" : "pending",
538
498
  turnId: request.turnId ?? definition.turnId ?? `credentials.${request.challengeId}`,
539
499
  ...(request.expiresAt ? { expiresAt: request.expiresAt } : {}),
540
- ...(request.hintKey ?? definition.hintKey
500
+ ...((request.hintKey ?? definition.hintKey)
541
501
  ? { hintKey: request.hintKey ?? definition.hintKey }
542
502
  : {}),
543
- ...(request.timing ?? definition.timing
503
+ ...((request.timing ?? definition.timing)
544
504
  ? { timing: request.timing ?? definition.timing }
545
505
  : {}),
546
506
  ...(expectedInput ? { expectedInput } : {}),
@@ -630,13 +590,7 @@ async function continuePendingChallenge<TCredentialKeys extends readonly string[
630
590
  normalizeInput(definition.fields, rawInput),
631
591
  pending.state,
632
592
  );
633
- return await resolveAuthResult(
634
- ctx,
635
- credentialKeys,
636
- challenges,
637
- result,
638
- completeTurnId,
639
- );
593
+ return await resolveAuthResult(ctx, credentialKeys, challenges, result, completeTurnId);
640
594
  }
641
595
 
642
596
  async function pollPendingChallenge<TCredentialKeys extends readonly string[]>(
@@ -669,13 +623,7 @@ async function pollPendingChallenge<TCredentialKeys extends readonly string[]>(
669
623
  `credentials.${pending.challengeId}.pending`,
670
624
  };
671
625
  }
672
- return await resolveAuthResult(
673
- ctx,
674
- credentialKeys,
675
- challenges,
676
- result,
677
- completeTurnId,
678
- );
626
+ return await resolveAuthResult(ctx, credentialKeys, challenges, result, completeTurnId);
679
627
  }
680
628
 
681
629
  export function defineCredentialsAuth<
@@ -697,7 +645,7 @@ export function defineCredentialsAuth<
697
645
  ): DefinedCredentialsAuth {
698
646
  if (Object.keys(options.fields).length === 0) {
699
647
  throw new ProviderError("defineCredentialsAuth requires at least one field", {
700
- fix: "Pass fields such as { email: { type: \"email\" }, password: { type: \"password\" } }.",
648
+ fix: 'Pass fields such as { email: { type: "email" }, password: { type: "password" } }.',
701
649
  });
702
650
  }
703
651
 
@@ -737,10 +685,7 @@ export function defineCredentialsAuth<
737
685
  return retryTurn(expectedInput, missing, retryTurnId);
738
686
  }
739
687
 
740
- const result = await options.login(
741
- ctx,
742
- normalizeInput(options.fields, rawInput),
743
- );
688
+ const result = await options.login(ctx, normalizeInput(options.fields, rawInput));
744
689
  return await resolveAuthResult(
745
690
  ctx,
746
691
  options.credentialKeys,
@@ -776,10 +721,7 @@ export function defineCredentialsAuth<
776
721
  },
777
722
  context: {
778
723
  keys: Array.from(
779
- new Set([
780
- CREDENTIALS_AUTH_CHALLENGE_CONTEXT_KEY,
781
- ...(options.contextKeys ?? []),
782
- ]),
724
+ new Set([CREDENTIALS_AUTH_CHALLENGE_CONTEXT_KEY, ...(options.contextKeys ?? [])]),
783
725
  ),
784
726
  },
785
727
  };
@@ -2,19 +2,14 @@ import { createHash, randomBytes, randomUUID } from "node:crypto";
2
2
 
3
3
  import Ajv2020 from "ajv/dist/2020.js";
4
4
 
5
- import { AUTH_TURN_SCHEMA, type KnownAuthTurnKind } from "../auth-turn";
5
+ import { AUTH_TURN_SCHEMA, type KnownAuthTurnKind } from "../auth-turn/index.js";
6
6
  import {
7
7
  FlowExpiredError,
8
8
  ProviderSecretError,
9
9
  TurnValidationError,
10
10
  ValidationError,
11
- } from "../errors";
12
- import type {
13
- AuthFlowDefinition,
14
- AuthFlowInputHandler,
15
- AuthTurn,
16
- FlowContext,
17
- } from "../types";
11
+ } from "../errors.js";
12
+ import type { AuthFlowDefinition, AuthFlowInputHandler, AuthTurn, FlowContext } from "../types.js";
18
13
 
19
14
  type TurnKind = KnownAuthTurnKind;
20
15
 
@@ -31,6 +26,15 @@ const validateAuthTurn = ajv.compile(AUTH_TURN_SCHEMA);
31
26
 
32
27
  const OAUTH2_STATE_KEY = "__oauth2_state";
33
28
  const OAUTH2_PKCE_VERIFIER_KEY = "__oauth2_pkce_verifier";
29
+ export const OAUTH2_PROXIED_AUTH_PROXY_ORIGIN_ENV_KEY = "APIFUSE__AUTH_PROXY__URL";
30
+ export const OAUTH2_PROXIED_PKCE_VERIFIER_KEY = "__oauth2_proxied_pkce_verifier";
31
+ const OAUTH2_PROXIED_RESERVED_AUTHORIZE_PARAMS = new Set([
32
+ "client_id",
33
+ "response_type",
34
+ "state",
35
+ "code_challenge",
36
+ "code_challenge_method",
37
+ ]);
34
38
  const DEVICE_FLOW_KEY = "__device_flow";
35
39
  const MAGIC_LINK_KEY = "__magic_link";
36
40
  const COMBINED_STAGE_KEY = "__combined_stage";
@@ -45,10 +49,7 @@ function ensureRecord(value: unknown): JsonObject {
45
49
  return isRecord(value) ? value : {};
46
50
  }
47
51
 
48
- function createTurn(
49
- kind: TurnKind,
50
- options: Omit<AuthTurn, "kind" | "turnId"> = {},
51
- ): AuthTurn {
52
+ function createTurn(kind: TurnKind, options: Omit<AuthTurn, "kind" | "turnId"> = {}): AuthTurn {
52
53
  return {
53
54
  kind,
54
55
  turnId: randomUUID(),
@@ -69,11 +70,7 @@ function getRequiredEnv(ctx: FlowContext, key: string): string {
69
70
  }
70
71
 
71
72
  function toBase64Url(input: Buffer): string {
72
- return input
73
- .toString("base64")
74
- .replace(/\+/g, "-")
75
- .replace(/\//g, "_")
76
- .replace(/=+$/g, "");
73
+ return input.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
77
74
  }
78
75
 
79
76
  function createCodeVerifier(): string {
@@ -130,10 +127,7 @@ async function runCeremonyHandler(
130
127
  }
131
128
  }
132
129
 
133
- function getString(
134
- input: Record<string, unknown>,
135
- key: string,
136
- ): string | undefined {
130
+ function getString(input: Record<string, unknown>, key: string): string | undefined {
137
131
  const value = input[key];
138
132
  return typeof value === "string" ? value : undefined;
139
133
  }
@@ -142,10 +136,7 @@ function getNestedRecord(ctx: FlowContext, key: string): JsonObject {
142
136
  return ensureRecord(ctx.context.get(key));
143
137
  }
144
138
 
145
- function buildJsonSchemaForm(
146
- expectedInput: JsonObject,
147
- hint: string,
148
- ): AuthTurn {
139
+ function buildJsonSchemaForm(expectedInput: JsonObject, hint: string): AuthTurn {
149
140
  return createTurn("form", {
150
141
  hint,
151
142
  expectedInput: withDeclaredFormFieldOrder(expectedInput),
@@ -160,10 +151,7 @@ function withDeclaredFormFieldOrder(expectedInput: JsonObject): JsonObject {
160
151
  }
161
152
 
162
153
  const existingOrder = expectedInput[FORM_FIELD_ORDER_EXTENSION];
163
- if (
164
- Array.isArray(existingOrder) &&
165
- existingOrder.every((value) => typeof value === "string")
166
- ) {
154
+ if (Array.isArray(existingOrder) && existingOrder.every((value) => typeof value === "string")) {
167
155
  return expectedInput;
168
156
  }
169
157
 
@@ -176,9 +164,7 @@ function withDeclaredFormFieldOrder(expectedInput: JsonObject): JsonObject {
176
164
  export function validateCeremonyOutput(turn: unknown): AuthTurn {
177
165
  if (!validateAuthTurn(turn)) {
178
166
  const detail = validateAuthTurn.errors
179
- ?.map(
180
- (error) => `${error.instancePath || "$"} ${error.message ?? "invalid"}`,
181
- )
167
+ ?.map((error) => `${error.instancePath || "$"} ${error.message ?? "invalid"}`)
182
168
  .join("; ");
183
169
  throw new TurnValidationError(detail || "Invalid AuthTurn output");
184
170
  }
@@ -214,10 +200,7 @@ export function createOAuth2Ceremony(options: {
214
200
  if (options.usePKCE) {
215
201
  const verifier = createCodeVerifier();
216
202
  ctx.context.set(OAUTH2_PKCE_VERIFIER_KEY, verifier);
217
- authorizeUrl.searchParams.set(
218
- "code_challenge",
219
- createCodeChallenge(verifier),
220
- );
203
+ authorizeUrl.searchParams.set("code_challenge", createCodeChallenge(verifier));
221
204
  authorizeUrl.searchParams.set("code_challenge_method", "S256");
222
205
  }
223
206
 
@@ -270,13 +253,80 @@ export function createOAuth2Ceremony(options: {
270
253
  ctx,
271
254
  input,
272
255
  ),
273
- abort: async () =>
274
- validateCeremonyOutput(
275
- createTurn("abort", { hint: "OAuth flow aborted." }),
276
- ),
256
+ abort: async () => validateCeremonyOutput(createTurn("abort", { hint: "OAuth flow aborted." })),
277
257
  };
278
258
  }
279
259
 
260
+ /**
261
+ * Builds the start handler for a custom-scheme OAuth provider. The shared
262
+ * auth-proxy owns state minting and callback capture, while the provider owns
263
+ * token exchange and any following authentication turns.
264
+ */
265
+ export function createOAuth2ProxiedStart(
266
+ options: import("../types.js").ProxiedOAuthConfig,
267
+ ): import("../types.js").AuthFlowStartHandler {
268
+ const pkce = options.pkce ?? "S256";
269
+
270
+ return (ctx) =>
271
+ runCeremonyHandler(
272
+ async () => {
273
+ for (const key of Object.keys(options.authorizeParams ?? {})) {
274
+ if (OAUTH2_PROXIED_RESERVED_AUTHORIZE_PARAMS.has(key.toLowerCase())) {
275
+ throw new ValidationError(
276
+ `OAuth2 proxied authorizeParams cannot override reserved parameter "${key}".`,
277
+ );
278
+ }
279
+ }
280
+ const proxyOrigin = ctx.env.get(OAUTH2_PROXIED_AUTH_PROXY_ORIGIN_ENV_KEY);
281
+ if (!proxyOrigin) {
282
+ throw new ProviderSecretError(
283
+ `Missing required platform environment: ${OAUTH2_PROXIED_AUTH_PROXY_ORIGIN_ENV_KEY}`,
284
+ );
285
+ }
286
+ const clientId = getRequiredEnv(ctx, options.clientIdEnvKey);
287
+ if (!ctx.flowId) {
288
+ throw new ValidationError(
289
+ "OAuth2 proxied start requires the gateway flow id.",
290
+ );
291
+ }
292
+
293
+ const authorizePath = new URL(options.authorizeUrl).pathname;
294
+ const url = new URL(
295
+ `/p/${encodeURIComponent(ctx.providerId)}/f/${encodeURIComponent(ctx.flowId)}${authorizePath}`,
296
+ proxyOrigin,
297
+ );
298
+ url.searchParams.set("client_id", clientId);
299
+ url.searchParams.set("response_type", "code");
300
+
301
+ if (pkce === "S256") {
302
+ const verifier = createCodeVerifier();
303
+ ctx.context.set(OAUTH2_PROXIED_PKCE_VERIFIER_KEY, verifier);
304
+ url.searchParams.set("code_challenge", createCodeChallenge(verifier));
305
+ url.searchParams.set("code_challenge_method", "S256");
306
+ }
307
+
308
+ for (const [key, value] of Object.entries(options.authorizeParams ?? {})) {
309
+ url.searchParams.set(key, value);
310
+ }
311
+
312
+ return createTurn("redirect", {
313
+ data: { url: url.toString() },
314
+ hint: "Open the provider authorization page to continue.",
315
+ expectedInput: {
316
+ type: "object",
317
+ required: ["code", "state"],
318
+ properties: {
319
+ code: { type: "string" },
320
+ state: { type: "string" },
321
+ },
322
+ },
323
+ });
324
+ },
325
+ "OAuth2 proxied start failed",
326
+ ctx,
327
+ );
328
+ }
329
+
280
330
  export function createDeviceFlowCeremony(options: {
281
331
  deviceCodeUrl: string;
282
332
  tokenUrl: string;
@@ -329,26 +379,19 @@ export function createDeviceFlowCeremony(options: {
329
379
  client_id: getRequiredEnv(ctx, options.clientIdEnvKey),
330
380
  ...(options.clientSecretEnvKey
331
381
  ? {
332
- client_secret: getRequiredEnv(
333
- ctx,
334
- options.clientSecretEnvKey,
335
- ),
382
+ client_secret: getRequiredEnv(ctx, options.clientSecretEnvKey),
336
383
  }
337
384
  : {}),
338
385
  });
339
386
  const data = ensureRecord(response.data);
340
387
  const errorCode = getString(data, "error");
341
388
 
342
- if (
343
- errorCode === "authorization_pending" ||
344
- errorCode === "slow_down"
345
- ) {
389
+ if (errorCode === "authorization_pending" || errorCode === "slow_down") {
346
390
  return createTurn("poll", {
347
391
  data,
348
392
  hint: "Authorization pending.",
349
393
  timing: {
350
- suggestedPollIntervalMs:
351
- errorCode === "slow_down" ? 10_000 : 5_000,
394
+ suggestedPollIntervalMs: errorCode === "slow_down" ? 10_000 : 5_000,
352
395
  maxWaitMs: 120_000,
353
396
  },
354
397
  });
@@ -367,9 +410,7 @@ export function createDeviceFlowCeremony(options: {
367
410
  ctx,
368
411
  ),
369
412
  abort: async () =>
370
- validateCeremonyOutput(
371
- createTurn("abort", { hint: "Device flow aborted." }),
372
- ),
413
+ validateCeremonyOutput(createTurn("abort", { hint: "Device flow aborted." })),
373
414
  };
374
415
  }
375
416
 
@@ -437,9 +478,7 @@ export function createWebAuthnCeremony(options: {
437
478
  input,
438
479
  ),
439
480
  abort: async () =>
440
- validateCeremonyOutput(
441
- createTurn("abort", { hint: "WebAuthn ceremony aborted." }),
442
- ),
481
+ validateCeremonyOutput(createTurn("abort", { hint: "WebAuthn ceremony aborted." })),
443
482
  };
444
483
  }
445
484
 
@@ -526,9 +565,7 @@ export function createMagicLinkCeremony(options: {
526
565
  ctx,
527
566
  ),
528
567
  abort: async () =>
529
- validateCeremonyOutput(
530
- createTurn("abort", { hint: "Magic link flow aborted." }),
531
- ),
568
+ validateCeremonyOutput(createTurn("abort", { hint: "Magic link flow aborted." })),
532
569
  };
533
570
  }
534
571
 
@@ -548,7 +585,7 @@ export function createFormCeremony(options: {
548
585
  continue: (ctx, input = {}) =>
549
586
  runCeremonyHandler(
550
587
  async () => {
551
- const { prevalidate } = await import("../runtime/prevalidate");
588
+ const { prevalidate } = await import("../runtime/prevalidate.js");
552
589
  const result = prevalidate(options.schema, input);
553
590
  if (!result.valid) {
554
591
  throw new ValidationError("Form input failed validation.", {
@@ -558,9 +595,7 @@ export function createFormCeremony(options: {
558
595
 
559
596
  return createTurn("complete", {
560
597
  data: {
561
- credential: options.mapCredential
562
- ? options.mapCredential(input)
563
- : input,
598
+ credential: options.mapCredential ? options.mapCredential(input) : input,
564
599
  },
565
600
  hint: "Form completed.",
566
601
  });
@@ -570,15 +605,11 @@ export function createFormCeremony(options: {
570
605
  input,
571
606
  ),
572
607
  abort: async () =>
573
- validateCeremonyOutput(
574
- createTurn("abort", { hint: "Form ceremony aborted." }),
575
- ),
608
+ validateCeremonyOutput(createTurn("abort", { hint: "Form ceremony aborted." })),
576
609
  };
577
610
  }
578
611
 
579
- export function combineCeremonies(
580
- ...ceremonies: AuthFlowDefinition[]
581
- ): AuthFlowDefinition {
612
+ export function combineCeremonies(...ceremonies: AuthFlowDefinition[]): AuthFlowDefinition {
582
613
  function getStage(ctx: FlowContext): number {
583
614
  const rawStage = ctx.context.get(COMBINED_STAGE_KEY);
584
615
  return typeof rawStage === "number" ? rawStage : 0;
@@ -630,9 +661,7 @@ export function combineCeremonies(
630
661
  async () => {
631
662
  const current = ceremonies[getStage(ctx)];
632
663
  if (!current?.poll) {
633
- throw new ValidationError(
634
- "Current ceremony does not support polling.",
635
- );
664
+ throw new ValidationError("Current ceremony does not support polling.");
636
665
  }
637
666
  return await current.poll(ctx);
638
667
  },
@@ -680,9 +709,7 @@ export function createSwitchCeremony(options: {
680
709
  async () => {
681
710
  const storedChoice = ctx.context.get(SWITCH_SELECTION_KEY);
682
711
  const choice =
683
- typeof storedChoice === "string"
684
- ? storedChoice
685
- : getString(input, "choice");
712
+ typeof storedChoice === "string" ? storedChoice : getString(input, "choice");
686
713
 
687
714
  if (!choice || !options.choices[choice]) {
688
715
  throw new ValidationError("A valid choice is required.");
@@ -710,9 +737,7 @@ export function createSwitchCeremony(options: {
710
737
 
711
738
  const ceremony = options.choices[choice];
712
739
  if (!ceremony?.poll) {
713
- throw new ValidationError(
714
- "Selected ceremony does not support polling.",
715
- );
740
+ throw new ValidationError("Selected ceremony does not support polling.");
716
741
  }
717
742
 
718
743
  return await ceremony.poll(ctx);
@@ -2,6 +2,7 @@ export type ApifuseCommandName =
2
2
  | "create"
3
3
  | "dev"
4
4
  | "check"
5
+ | "sync-assets"
5
6
  | "submit-check"
6
7
  | "bounty-check"
7
8
  | "record"
@@ -46,6 +47,14 @@ export const COMMAND_MANIFEST: Record<
46
47
  examples: ["apifuse check .", "apifuse check providers/korea-air-quality"],
47
48
  modulePath: "./apifuse-check",
48
49
  },
50
+ "sync-assets": {
51
+ name: "sync-assets",
52
+ summary:
53
+ "Regenerate SDK-managed agent prompt assets (AGENTS.md, .agents/skills, symlinks, manifest) for the installed SDK version.",
54
+ usage: "apifuse sync-assets [path] [--check]",
55
+ examples: ["apifuse sync-assets .", "apifuse sync-assets . --check"],
56
+ modulePath: "./apifuse-sync-assets",
57
+ },
49
58
  "submit-check": {
50
59
  name: "submit-check",
51
60
  summary:
@@ -103,6 +112,7 @@ export const COMMAND_ORDER: ApifuseCommandName[] = [
103
112
  "create",
104
113
  "dev",
105
114
  "check",
115
+ "sync-assets",
106
116
  "submit-check",
107
117
  "record",
108
118
  "test",