@yolk-sdk/emulators 0.1.0-canary.96

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 (333) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +2135 -0
  3. package/dist/anthropic.d.mts +269 -0
  4. package/dist/anthropic.d.mts.map +1 -0
  5. package/dist/anthropic.mjs +177 -0
  6. package/dist/anthropic.mjs.map +1 -0
  7. package/dist/chat-completions.d.mts +288 -0
  8. package/dist/chat-completions.d.mts.map +1 -0
  9. package/dist/chat-completions.mjs +451 -0
  10. package/dist/chat-completions.mjs.map +1 -0
  11. package/dist/codex.d.mts +265 -0
  12. package/dist/codex.d.mts.map +1 -0
  13. package/dist/codex.mjs +199 -0
  14. package/dist/codex.mjs.map +1 -0
  15. package/dist/dropbox/api.d.mts +63 -0
  16. package/dist/dropbox/api.d.mts.map +1 -0
  17. package/dist/dropbox/api.mjs +565 -0
  18. package/dist/dropbox/api.mjs.map +1 -0
  19. package/dist/dropbox/state.d.mts +136 -0
  20. package/dist/dropbox/state.d.mts.map +1 -0
  21. package/dist/dropbox/state.mjs +209 -0
  22. package/dist/dropbox/state.mjs.map +1 -0
  23. package/dist/dropbox.d.mts +79 -0
  24. package/dist/dropbox.d.mts.map +1 -0
  25. package/dist/dropbox.mjs +124 -0
  26. package/dist/dropbox.mjs.map +1 -0
  27. package/dist/email-fixtures.d.mts +36 -0
  28. package/dist/email-fixtures.d.mts.map +1 -0
  29. package/dist/email-fixtures.mjs +1080 -0
  30. package/dist/email-fixtures.mjs.map +1 -0
  31. package/dist/email.d.mts +160 -0
  32. package/dist/email.d.mts.map +1 -0
  33. package/dist/email.mjs +608 -0
  34. package/dist/email.mjs.map +1 -0
  35. package/dist/emulator-compose.d.mts +40 -0
  36. package/dist/emulator-compose.d.mts.map +1 -0
  37. package/dist/emulator-compose.mjs +91 -0
  38. package/dist/emulator-compose.mjs.map +1 -0
  39. package/dist/emulator-http.d.mts +53 -0
  40. package/dist/emulator-http.d.mts.map +1 -0
  41. package/dist/emulator-http.mjs +117 -0
  42. package/dist/emulator-http.mjs.map +1 -0
  43. package/dist/emulator-kernel.d.mts +176 -0
  44. package/dist/emulator-kernel.d.mts.map +1 -0
  45. package/dist/emulator-kernel.mjs +413 -0
  46. package/dist/emulator-kernel.mjs.map +1 -0
  47. package/dist/fixture-route.d.mts +129 -0
  48. package/dist/fixture-route.d.mts.map +1 -0
  49. package/dist/fixture-route.mjs +257 -0
  50. package/dist/fixture-route.mjs.map +1 -0
  51. package/dist/fortnox/api.d.mts +92 -0
  52. package/dist/fortnox/api.d.mts.map +1 -0
  53. package/dist/fortnox/api.mjs +750 -0
  54. package/dist/fortnox/api.mjs.map +1 -0
  55. package/dist/fortnox/state.d.mts +533 -0
  56. package/dist/fortnox/state.d.mts.map +1 -0
  57. package/dist/fortnox/state.mjs +612 -0
  58. package/dist/fortnox/state.mjs.map +1 -0
  59. package/dist/fortnox.d.mts +128 -0
  60. package/dist/fortnox.d.mts.map +1 -0
  61. package/dist/fortnox.mjs +403 -0
  62. package/dist/fortnox.mjs.map +1 -0
  63. package/dist/gateway-evaluate-recordings.d.mts +12 -0
  64. package/dist/gateway-evaluate-recordings.d.mts.map +1 -0
  65. package/dist/gateway-evaluate-recordings.mjs +128 -0
  66. package/dist/gateway-evaluate-recordings.mjs.map +1 -0
  67. package/dist/gateway.d.mts +272 -0
  68. package/dist/gateway.d.mts.map +1 -0
  69. package/dist/gateway.mjs +400 -0
  70. package/dist/gateway.mjs.map +1 -0
  71. package/dist/github/api.d.mts +63 -0
  72. package/dist/github/api.d.mts.map +1 -0
  73. package/dist/github/api.mjs +527 -0
  74. package/dist/github/api.mjs.map +1 -0
  75. package/dist/github/state.d.mts +272 -0
  76. package/dist/github/state.d.mts.map +1 -0
  77. package/dist/github/state.mjs +303 -0
  78. package/dist/github/state.mjs.map +1 -0
  79. package/dist/github.d.mts +77 -0
  80. package/dist/github.d.mts.map +1 -0
  81. package/dist/github.mjs +180 -0
  82. package/dist/github.mjs.map +1 -0
  83. package/dist/google/calendar.d.mts +10 -0
  84. package/dist/google/calendar.d.mts.map +1 -0
  85. package/dist/google/calendar.mjs +252 -0
  86. package/dist/google/calendar.mjs.map +1 -0
  87. package/dist/google/drive.d.mts +8 -0
  88. package/dist/google/drive.d.mts.map +1 -0
  89. package/dist/google/drive.mjs +252 -0
  90. package/dist/google/drive.mjs.map +1 -0
  91. package/dist/google/gmail.d.mts +10 -0
  92. package/dist/google/gmail.d.mts.map +1 -0
  93. package/dist/google/gmail.mjs +591 -0
  94. package/dist/google/gmail.mjs.map +1 -0
  95. package/dist/google/shared.d.mts +107 -0
  96. package/dist/google/shared.d.mts.map +1 -0
  97. package/dist/google/shared.mjs +146 -0
  98. package/dist/google/shared.mjs.map +1 -0
  99. package/dist/google/state.d.mts +385 -0
  100. package/dist/google/state.d.mts.map +1 -0
  101. package/dist/google/state.mjs +496 -0
  102. package/dist/google/state.mjs.map +1 -0
  103. package/dist/google.d.mts +75 -0
  104. package/dist/google.d.mts.map +1 -0
  105. package/dist/google.mjs +210 -0
  106. package/dist/google.mjs.map +1 -0
  107. package/dist/linkedin-search/api.d.mts +45 -0
  108. package/dist/linkedin-search/api.d.mts.map +1 -0
  109. package/dist/linkedin-search/api.mjs +181 -0
  110. package/dist/linkedin-search/api.mjs.map +1 -0
  111. package/dist/linkedin-search/state.d.mts +123 -0
  112. package/dist/linkedin-search/state.d.mts.map +1 -0
  113. package/dist/linkedin-search/state.mjs +261 -0
  114. package/dist/linkedin-search/state.mjs.map +1 -0
  115. package/dist/linkedin-search.d.mts +69 -0
  116. package/dist/linkedin-search.d.mts.map +1 -0
  117. package/dist/linkedin-search.mjs +158 -0
  118. package/dist/linkedin-search.mjs.map +1 -0
  119. package/dist/mcp/api.d.mts +44 -0
  120. package/dist/mcp/api.d.mts.map +1 -0
  121. package/dist/mcp/api.mjs +557 -0
  122. package/dist/mcp/api.mjs.map +1 -0
  123. package/dist/mcp/recordings.d.mts +40 -0
  124. package/dist/mcp/recordings.d.mts.map +1 -0
  125. package/dist/mcp/recordings.mjs +2390 -0
  126. package/dist/mcp/recordings.mjs.map +1 -0
  127. package/dist/mcp/state.d.mts +71 -0
  128. package/dist/mcp/state.d.mts.map +1 -0
  129. package/dist/mcp/state.mjs +83 -0
  130. package/dist/mcp/state.mjs.map +1 -0
  131. package/dist/mcp.d.mts +84 -0
  132. package/dist/mcp.d.mts.map +1 -0
  133. package/dist/mcp.mjs +241 -0
  134. package/dist/mcp.mjs.map +1 -0
  135. package/dist/messages.d.mts +183 -0
  136. package/dist/messages.d.mts.map +1 -0
  137. package/dist/messages.mjs +532 -0
  138. package/dist/messages.mjs.map +1 -0
  139. package/dist/microsoft/api.d.mts +47 -0
  140. package/dist/microsoft/api.d.mts.map +1 -0
  141. package/dist/microsoft/api.mjs +178 -0
  142. package/dist/microsoft/api.mjs.map +1 -0
  143. package/dist/microsoft/calendar.d.mts +30 -0
  144. package/dist/microsoft/calendar.d.mts.map +1 -0
  145. package/dist/microsoft/calendar.mjs +271 -0
  146. package/dist/microsoft/calendar.mjs.map +1 -0
  147. package/dist/microsoft/drive.d.mts +36 -0
  148. package/dist/microsoft/drive.d.mts.map +1 -0
  149. package/dist/microsoft/drive.mjs +298 -0
  150. package/dist/microsoft/drive.mjs.map +1 -0
  151. package/dist/microsoft/graph.d.mts +198 -0
  152. package/dist/microsoft/graph.d.mts.map +1 -0
  153. package/dist/microsoft/graph.mjs +264 -0
  154. package/dist/microsoft/graph.mjs.map +1 -0
  155. package/dist/microsoft/mail.d.mts +48 -0
  156. package/dist/microsoft/mail.d.mts.map +1 -0
  157. package/dist/microsoft/mail.mjs +488 -0
  158. package/dist/microsoft/mail.mjs.map +1 -0
  159. package/dist/microsoft/state.d.mts +480 -0
  160. package/dist/microsoft/state.d.mts.map +1 -0
  161. package/dist/microsoft/state.mjs +625 -0
  162. package/dist/microsoft/state.mjs.map +1 -0
  163. package/dist/microsoft.d.mts +168 -0
  164. package/dist/microsoft.d.mts.map +1 -0
  165. package/dist/microsoft.mjs +483 -0
  166. package/dist/microsoft.mjs.map +1 -0
  167. package/dist/node.d.mts +47 -0
  168. package/dist/node.d.mts.map +1 -0
  169. package/dist/node.mjs +178 -0
  170. package/dist/node.mjs.map +1 -0
  171. package/dist/notion/api.d.mts +51 -0
  172. package/dist/notion/api.d.mts.map +1 -0
  173. package/dist/notion/api.mjs +507 -0
  174. package/dist/notion/api.mjs.map +1 -0
  175. package/dist/notion/state.d.mts +329 -0
  176. package/dist/notion/state.d.mts.map +1 -0
  177. package/dist/notion/state.mjs +432 -0
  178. package/dist/notion/state.mjs.map +1 -0
  179. package/dist/notion.d.mts +72 -0
  180. package/dist/notion.d.mts.map +1 -0
  181. package/dist/notion.mjs +127 -0
  182. package/dist/notion.mjs.map +1 -0
  183. package/dist/openai.d.mts +165 -0
  184. package/dist/openai.d.mts.map +1 -0
  185. package/dist/openai.mjs +141 -0
  186. package/dist/openai.mjs.map +1 -0
  187. package/dist/opencode-recordings.d.mts +7 -0
  188. package/dist/opencode-recordings.d.mts.map +1 -0
  189. package/dist/opencode-recordings.mjs +222 -0
  190. package/dist/opencode-recordings.mjs.map +1 -0
  191. package/dist/opencode.d.mts +70 -0
  192. package/dist/opencode.d.mts.map +1 -0
  193. package/dist/opencode.mjs +217 -0
  194. package/dist/opencode.mjs.map +1 -0
  195. package/dist/r2-fixtures.d.mts +36 -0
  196. package/dist/r2-fixtures.d.mts.map +1 -0
  197. package/dist/r2-fixtures.mjs +245 -0
  198. package/dist/r2-fixtures.mjs.map +1 -0
  199. package/dist/r2-guard.d.mts +43 -0
  200. package/dist/r2-guard.d.mts.map +1 -0
  201. package/dist/r2-guard.mjs +215 -0
  202. package/dist/r2-guard.mjs.map +1 -0
  203. package/dist/r2.d.mts +166 -0
  204. package/dist/r2.d.mts.map +1 -0
  205. package/dist/r2.mjs +517 -0
  206. package/dist/r2.mjs.map +1 -0
  207. package/dist/responses.d.mts +231 -0
  208. package/dist/responses.d.mts.map +1 -0
  209. package/dist/responses.mjs +556 -0
  210. package/dist/responses.mjs.map +1 -0
  211. package/dist/route-evidence.d.mts +45 -0
  212. package/dist/route-evidence.d.mts.map +1 -0
  213. package/dist/route-evidence.mjs +56 -0
  214. package/dist/route-evidence.mjs.map +1 -0
  215. package/dist/router.d.mts +93 -0
  216. package/dist/router.d.mts.map +1 -0
  217. package/dist/router.mjs +259 -0
  218. package/dist/router.mjs.map +1 -0
  219. package/dist/stateful-core.d.mts +17 -0
  220. package/dist/stateful-core.d.mts.map +1 -0
  221. package/dist/stateful-core.mjs +41 -0
  222. package/dist/stateful-core.mjs.map +1 -0
  223. package/dist/stateful-emulator.d.mts +565 -0
  224. package/dist/stateful-emulator.d.mts.map +1 -0
  225. package/dist/stateful-emulator.mjs +1228 -0
  226. package/dist/stateful-emulator.mjs.map +1 -0
  227. package/dist/stateful-secrets.d.mts +84 -0
  228. package/dist/stateful-secrets.d.mts.map +1 -0
  229. package/dist/stateful-secrets.mjs +216 -0
  230. package/dist/stateful-secrets.mjs.map +1 -0
  231. package/dist/subscription-usage-recordings.d.mts +9 -0
  232. package/dist/subscription-usage-recordings.d.mts.map +1 -0
  233. package/dist/subscription-usage-recordings.mjs +53 -0
  234. package/dist/subscription-usage-recordings.mjs.map +1 -0
  235. package/dist/subscription-usage.d.mts +53 -0
  236. package/dist/subscription-usage.d.mts.map +1 -0
  237. package/dist/subscription-usage.mjs +21 -0
  238. package/dist/subscription-usage.mjs.map +1 -0
  239. package/dist/telegram/api.d.mts +34 -0
  240. package/dist/telegram/api.d.mts.map +1 -0
  241. package/dist/telegram/api.mjs +257 -0
  242. package/dist/telegram/api.mjs.map +1 -0
  243. package/dist/telegram/state.d.mts +128 -0
  244. package/dist/telegram/state.d.mts.map +1 -0
  245. package/dist/telegram/state.mjs +154 -0
  246. package/dist/telegram/state.mjs.map +1 -0
  247. package/dist/telegram.d.mts +62 -0
  248. package/dist/telegram.d.mts.map +1 -0
  249. package/dist/telegram.mjs +127 -0
  250. package/dist/telegram.mjs.map +1 -0
  251. package/dist/todoist/api.d.mts +55 -0
  252. package/dist/todoist/api.d.mts.map +1 -0
  253. package/dist/todoist/api.mjs +415 -0
  254. package/dist/todoist/api.mjs.map +1 -0
  255. package/dist/todoist/state.d.mts +275 -0
  256. package/dist/todoist/state.d.mts.map +1 -0
  257. package/dist/todoist/state.mjs +345 -0
  258. package/dist/todoist/state.mjs.map +1 -0
  259. package/dist/todoist.d.mts +68 -0
  260. package/dist/todoist.d.mts.map +1 -0
  261. package/dist/todoist.mjs +181 -0
  262. package/dist/todoist.mjs.map +1 -0
  263. package/dist/xai.d.mts +267 -0
  264. package/dist/xai.d.mts.map +1 -0
  265. package/dist/xai.mjs +252 -0
  266. package/dist/xai.mjs.map +1 -0
  267. package/package.json +157 -0
  268. package/src/anthropic.ts +289 -0
  269. package/src/chat-completions.ts +924 -0
  270. package/src/codex.ts +296 -0
  271. package/src/dropbox/api.ts +1084 -0
  272. package/src/dropbox/state.ts +364 -0
  273. package/src/dropbox.ts +203 -0
  274. package/src/email-fixtures.ts +1297 -0
  275. package/src/email.ts +1108 -0
  276. package/src/emulator-compose.ts +147 -0
  277. package/src/emulator-http.ts +184 -0
  278. package/src/emulator-kernel.ts +844 -0
  279. package/src/fixture-route.ts +561 -0
  280. package/src/fortnox/api.ts +1352 -0
  281. package/src/fortnox/state.ts +798 -0
  282. package/src/fortnox.ts +801 -0
  283. package/src/gateway-evaluate-recordings.ts +153 -0
  284. package/src/gateway.ts +530 -0
  285. package/src/github/api.ts +986 -0
  286. package/src/github/state.ts +439 -0
  287. package/src/github.ts +271 -0
  288. package/src/google/calendar.ts +486 -0
  289. package/src/google/drive.ts +471 -0
  290. package/src/google/gmail.ts +1011 -0
  291. package/src/google/shared.ts +321 -0
  292. package/src/google/state.ts +686 -0
  293. package/src/google.ts +298 -0
  294. package/src/linkedin-search/api.ts +363 -0
  295. package/src/linkedin-search/state.ts +373 -0
  296. package/src/linkedin-search.ts +241 -0
  297. package/src/mcp/api.ts +995 -0
  298. package/src/mcp/recordings.ts +2665 -0
  299. package/src/mcp/state.ts +125 -0
  300. package/src/mcp.ts +319 -0
  301. package/src/messages.ts +844 -0
  302. package/src/microsoft/api.ts +426 -0
  303. package/src/microsoft/calendar.ts +491 -0
  304. package/src/microsoft/drive.ts +541 -0
  305. package/src/microsoft/graph.ts +550 -0
  306. package/src/microsoft/mail.ts +833 -0
  307. package/src/microsoft/state.ts +822 -0
  308. package/src/microsoft.ts +982 -0
  309. package/src/node.ts +293 -0
  310. package/src/notion/api.ts +976 -0
  311. package/src/notion/state.ts +512 -0
  312. package/src/notion.ts +210 -0
  313. package/src/openai.ts +198 -0
  314. package/src/opencode-recordings.ts +257 -0
  315. package/src/opencode.ts +271 -0
  316. package/src/r2-fixtures.ts +295 -0
  317. package/src/r2-guard.ts +323 -0
  318. package/src/r2.ts +890 -0
  319. package/src/responses.ts +901 -0
  320. package/src/route-evidence.ts +90 -0
  321. package/src/router.ts +490 -0
  322. package/src/stateful-core.ts +70 -0
  323. package/src/stateful-emulator.ts +2571 -0
  324. package/src/stateful-secrets.ts +299 -0
  325. package/src/subscription-usage-recordings.ts +77 -0
  326. package/src/subscription-usage.ts +68 -0
  327. package/src/telegram/api.ts +437 -0
  328. package/src/telegram/state.ts +229 -0
  329. package/src/telegram.ts +227 -0
  330. package/src/todoist/api.ts +736 -0
  331. package/src/todoist/state.ts +456 -0
  332. package/src/todoist.ts +316 -0
  333. package/src/xai.ts +341 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fortnox.mjs","names":[],"sources":["../src/fortnox.ts"],"sourcesContent":["/**\n * Stateful Fortnox API emulator (`/3`), built on the upstream `@emulators/core` custom runtime,\n * with a request ledger, wire faults, and an `/_emulate/*` control plane.\n *\n * It never imports SDK code: its wire shapes and default seed are copied as data from the\n * synthetic Fortnox conformance fixtures, and every route names the conformance cases it follows\n * in `fortnoxEmulatorRoutes`. The observed Fortnox quirks those cases claim (sticky row discounts,\n * empty strings that keep values, payment filters that skip unbooked invoices, `ErrorInformation`\n * rejections, read-only `Country`) are implemented and listed in `fortnoxEmulatorQuirks`.\n *\n * Node-only: `@emulators/core` imports Node builtins, so the core is loaded lazily by\n * `makeFortnoxEmulator` (importing this module has no side effects).\n *\n * @experimental\n */\nimport type { EmulatorSnapshot } from '@emulators/core'\nimport { Data, Predicate, Result } from 'effect'\nimport * as Schema from 'effect/Schema'\nimport {\n EmulatorHeaderRecord,\n EmulatorResponseStatus,\n emulatorJobHeader,\n handlerFailedHeader\n} from './emulator-http.ts'\nimport {\n errorInformation,\n fortnoxApiRoutes,\n fortnoxEmulatorErrorCodes,\n matchFortnoxRoute,\n parseJsonText,\n registerFortnoxApi,\n type FortnoxApiEnv,\n type FortnoxEmulatorQuirks\n} from './fortnox/api.ts'\nimport {\n buildSeedState,\n decodeState,\n type FortnoxEmulatorSeed,\n type FortnoxEmulatorState\n} from './fortnox/state.ts'\nimport {\n emulatorEvidenceHeader,\n type EmulatorEvidence,\n type EmulatorRouteEvidence\n} from './route-evidence.ts'\n\nexport type { EmulatorEvidence, EmulatorRouteEvidence } from './route-evidence.ts'\n\nexport { emulatorEvidenceHeader } from './route-evidence.ts'\n\nexport {\n fortnoxEmulatorBasePath,\n fortnoxEmulatorErrorCodes,\n fortnoxEmulatorQuirks,\n type FortnoxEmulatorQuirk,\n type FortnoxEmulatorQuirks\n} from './fortnox/api.ts'\n\nexport {\n FortnoxEmulatorCompany,\n FortnoxEmulatorCustomer,\n FortnoxEmulatorCustomerSeed,\n FortnoxEmulatorInvoice,\n FortnoxEmulatorInvoiceRow,\n FortnoxEmulatorInvoiceRowSeed,\n FortnoxEmulatorInvoiceSeed,\n FortnoxEmulatorOutboxEntry,\n FortnoxEmulatorProfile,\n FortnoxEmulatorSeed,\n FortnoxEmulatorStateSchema,\n type FortnoxEmulatorState\n} from './fortnox/state.ts'\n\n/** Origin the connector calls; also the default origin of `@url` links. */\nexport const fortnoxEmulatorDefaultOrigin = 'https://api.fortnox.se'\n\n/**\n * Route evidence manifest: every emulated Fortnox route, whether it writes, and the conformance\n * cases whose (currently synthetic, unverified) wire claims it follows. Kept in sync with the\n * handlers by construction (both come from one route table).\n */\nexport const fortnoxEmulatorRoutes: ReadonlyArray<EmulatorRouteEvidence> = fortnoxApiRoutes.map(\n ({ handler: _handler, queryKeys: _queryKeys, ...route }) => route\n)\n\nconst FaultCount = Schema.Int.check(Schema.isGreaterThanOrEqualTo(1))\n\n/** Optional fault filter; an omitted field matches every request. `path` ending in `*` is a prefix. */\nexport const FortnoxFaultMatch = Schema.Struct({\n method: Schema.optionalKey(Schema.String),\n path: Schema.optionalKey(Schema.String)\n})\n\nexport type FortnoxFaultMatch = typeof FortnoxFaultMatch.Type\n\n/**\n * A wire fault: answer matching requests with this status, headers, and body (for example 429\n * with `retry-after`) instead of the route's successful answer, so nothing is written. A request\n * the route refuses is answered by the route and uses up no fault. The body defaults to a\n * Fortnox `ErrorInformation`. `count` limits how many requests it answers (omitted: all).\n *\n * The Gateway emulator's rules apply: statuses that cannot carry a body (1xx, 204, 205) and\n * redirects (3xx) are rejected, as are invalid header names or values, a `location` header, and\n * framing headers (`content-length`, `transfer-encoding`, `connection`, `keep-alive`, `upgrade`).\n */\nexport const FortnoxFault = Schema.Struct({\n kind: Schema.Literal('status'),\n status: EmulatorResponseStatus,\n headers: Schema.optionalKey(EmulatorHeaderRecord),\n body: Schema.optionalKey(Schema.Json),\n match: Schema.optionalKey(FortnoxFaultMatch),\n count: Schema.optionalKey(FaultCount)\n})\n\nexport type FortnoxFault = typeof FortnoxFault.Type\n\n/** Invalid emulator input from the JS API: a seed, a fault, or an option. A programmer error. */\nexport class FortnoxEmulatorInputInvalid extends Data.TaggedError('FortnoxEmulatorInputInvalid')<{\n readonly input: 'seed' | 'fault' | 'option'\n readonly reason: string\n}> {\n override get message(): string {\n return `Invalid Fortnox emulator ${this.input}: ${this.reason}`\n }\n}\n\nexport type FortnoxLedgerEntry = {\n /** 1-based arrival order since the last ledger clear or reset. */\n readonly seq: number\n readonly method: string\n /** Concrete request path, for example `/3/invoices/103`. */\n readonly path: string\n /** Path template of the matched route, for example `/3/invoices/{DocumentNumber}`. */\n readonly route?: string\n readonly query: Readonly<Record<string, string>>\n /** Parsed JSON request body, when there was one. */\n readonly body?: Schema.Json\n readonly status: number\n /** Evidence of the matched route; `unknown-route` for requests that failed closed. */\n readonly evidence: EmulatorEvidence | 'unknown-route'\n /** Set when a fault answered the request. */\n readonly fault?: 'status'\n /**\n * Set when the emulator could not build or produce the response, or a route handler threw; the\n * request was answered with a 500 `ErrorInformation` (still evidence-tagged) and no fault was\n * used up.\n */\n readonly responseError?: string\n}\n\nexport type FortnoxFaultState = {\n readonly id: number\n readonly fault: FortnoxFault\n /** Remaining matching requests; `undefined` for an unlimited fault. */\n readonly remaining: number | undefined\n readonly applied: number\n}\n\nexport type FortnoxRouteCoverage = EmulatorRouteEvidence & {\n /** Ledger requests answered by this route since the last ledger clear or reset. */\n readonly requests: number\n}\n\nexport type FortnoxCoverage = {\n readonly routes: ReadonlyArray<FortnoxRouteCoverage>\n /** Ledger requests to unknown routes (failed closed). */\n readonly unknownRouteRequests: number\n}\n\nexport type FortnoxEmulatorOptions = {\n /** Typed seed; defaults to the fixture entities (`profile: 'default'`). */\n readonly seed?: FortnoxEmulatorSeed\n /** Clock in epoch milliseconds. Defaults to `Date.now`. */\n readonly now?: () => number\n /** Drill knobs (tests only): flip one observed quirk to prove the cases catch it. */\n readonly quirks?: FortnoxEmulatorQuirks\n /** Origin of `@url` links in responses. Defaults to `https://api.fortnox.se`. */\n readonly baseUrl?: string\n}\n\nexport type FortnoxEmulator = {\n /** The fetch handler (the `/3` API plus the `/_emulate/*` control plane). Never rejects. */\n readonly fetch: (request: Request) => Promise<Response>\n /** Origin of `@url` links in responses. */\n readonly baseUrl: string\n readonly ledger: {\n readonly entries: () => ReadonlyArray<FortnoxLedgerEntry>\n readonly clear: () => void\n }\n readonly faults: {\n /** Add a fault; throws `FortnoxEmulatorInputInvalid` for an invalid fault. */\n readonly add: (fault: FortnoxFault) => FortnoxFaultState\n readonly list: () => ReadonlyArray<FortnoxFaultState>\n readonly clear: () => void\n }\n /** Restore the current seed and clear the ledger and faults. */\n readonly reset: () => Promise<void>\n /**\n * Replace the state with a new seed, which becomes what `reset` restores. Rejects with\n * `FortnoxEmulatorInputInvalid` for an invalid seed.\n */\n readonly seed: (seed: FortnoxEmulatorSeed) => Promise<void>\n /** A deep copy of the current state (entities, outbox, counters). */\n readonly snapshot: () => FortnoxEmulatorState\n readonly coverage: () => FortnoxCoverage\n /** Close the core runtime. Later requests answer 503. Idempotent. */\n readonly close: () => Promise<void>\n}\n\nconst strict = { onExcessProperty: 'error' } as const\n\nconst decodeFault = Schema.decodeUnknownResult(FortnoxFault, strict)\n\nconst decodeFaultList = Schema.decodeUnknownResult(\n Schema.Union([FortnoxFault, Schema.Struct({ faults: Schema.Array(FortnoxFault) })]),\n strict\n)\n\nconst issueMessage = (issue: Schema.SchemaError['issue']): string =>\n new Schema.SchemaError(issue).message\n\nconst jsonResponse = (status: number, body: unknown, headers: HeadersInit = {}): Response => {\n const responseHeaders = new Headers(headers)\n\n responseHeaders.set('content-type', 'application/json')\n\n return new Response(JSON.stringify(body), { status, headers: responseHeaders })\n}\n\nconst controlError = (status: number, message: string, headers: HeadersInit = {}): Response =>\n jsonResponse(status, { error: { message, type: 'emulator_error' } }, headers)\n\nconst codes = fortnoxEmulatorErrorCodes\n\nconst defaultFaultBody = (status: number): Schema.Json => ({\n ErrorInformation:\n status === 429\n ? { error: 1, message: 'Synthetic: too many requests.', code: codes.rateLimited }\n : { error: 1, message: `Synthetic upstream error (${status}).`, code: codes.upstreamError }\n})\n\n// A non-empty bearer credential. The value is never checked, stored, forwarded, or ledgered.\nconst bearerPattern = /^bearer\\s+\\S+/i\n\nconst pathMatches = (pattern: string, path: string): boolean =>\n pattern.endsWith('*') ? path.startsWith(pattern.slice(0, -1)) : pattern === path\n\nconst faultMatches = (fault: FortnoxFault, method: string, path: string): boolean =>\n (fault.match?.method === undefined || fault.match.method.toUpperCase() === method) &&\n (fault.match?.path === undefined || pathMatches(fault.match.path, path))\n\nconst readText = (request: Request): Promise<string | undefined> =>\n request.text().then(\n text => text,\n () => undefined\n )\n\nconst validOrigin = (input: string): string | undefined => {\n if (!URL.canParse(input)) {\n return undefined\n }\n\n const url = new URL(input)\n\n const bare =\n (url.pathname === '/' || url.pathname === '') &&\n url.search === '' &&\n url.hash === '' &&\n url.username === '' &&\n url.password === ''\n\n return (url.protocol === 'http:' || url.protocol === 'https:') && bare ? url.origin : undefined\n}\n\ntype MutableLedgerEntry = {\n seq: number\n method: string\n path: string\n route?: string\n query: Readonly<Record<string, string>>\n body?: Schema.Json\n status: number\n evidence: EmulatorEvidence | 'unknown-route'\n fault?: 'status'\n responseError?: string\n}\n\n/** One core request's fault outcome: the fault's answer, set when a fault answered it. */\ntype FaultJob = { faultAnswer?: Response }\n\ntype MutableFaultState = {\n readonly id: number\n readonly fault: FortnoxFault\n remaining: number | undefined\n applied: number\n}\n\nconst withEvidence = (response: Response, evidence: EmulatorEvidence): Response => {\n const headers = new Headers(response.headers)\n\n if (evidence === 'unverified') {\n headers.set(emulatorEvidenceHeader, 'unverified')\n }\n\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers\n })\n}\n\nconst defaultQuirks: Required<FortnoxEmulatorQuirks> = {\n stickyRowDiscount: true,\n emptyStringClears: false,\n paymentFiltersIncludeUnbooked: false\n}\n\n/** The evidence-tagged fallback when a matched API route cannot build or produce its response. */\nconst responseFailed = (): Response =>\n errorInformation(\n 500,\n codes.upstreamError,\n 'Synthetic: the emulator could not build the response.'\n )\n\nconst isControlPath = (path: string): boolean =>\n path === '/_emulate' || path.startsWith('/_emulate/')\n\n/**\n * Create a stateful Fortnox emulator on the `@emulators/core` custom runtime. Each call has its\n * own state, ledger, and faults. Rejects with `FortnoxEmulatorInputInvalid` for an invalid seed\n * or `baseUrl`.\n *\n * Requests to `/3/*` need `Authorization: Bearer <non-empty>` (missing: 401 `ErrorInformation`);\n * the token is never checked, stored, forwarded to the core, or ledgered. Precedence per request:\n * route match (unknown routes fail closed with a 404 `ErrorInformation`), authorization, JSON\n * body parsing, then the stateful route's plan (its query allowlist, then its handler on a draft\n * of the state), then the first matching fault, then the commit. A request the route refuses (any\n * answer that is not 2xx, such as a 404 for an unknown id or a 400 for an invalid state) uses up\n * no fault; a faulted request writes nothing. Every response from an unverified route carries\n * `x-emulator-evidence: unverified`.\n */\nexport const makeFortnoxEmulator = async (\n options: FortnoxEmulatorOptions = {}\n): Promise<FortnoxEmulator> => {\n const initial = buildSeedState(options.seed ?? {})\n\n if (Predicate.isString(initial)) {\n throw new FortnoxEmulatorInputInvalid({ input: 'seed', reason: initial })\n }\n\n const linkOrigin = validOrigin(options.baseUrl ?? fortnoxEmulatorDefaultOrigin)\n\n if (linkOrigin === undefined) {\n throw new FortnoxEmulatorInputInvalid({\n input: 'option',\n reason: 'baseUrl must be an http(s) origin without path, query, hash, or credentials'\n })\n }\n\n const env: FortnoxApiEnv = {\n now: options.now ?? (() => Date.now()),\n linkOrigin,\n quirks: { ...defaultQuirks, ...options.quirks }\n }\n\n // Loaded lazily: the core imports Node builtins and reads files at import time.\n const core = await import('@emulators/core')\n\n /**\n * Fault decisions of the core requests in flight, by job id (asked by the route once it would\n * answer successfully). Job ids never reset, so a ledger clear never makes two jobs share one.\n */\n const jobs = new Map<string, () => boolean>()\n let nextJobId = 1\n\n const definition = core.defineEmulator<FortnoxEmulatorState>({\n name: 'fortnox',\n cors: false,\n state: () => initial,\n validateSeed: value => {\n const decoded = decodeState(value)\n\n if (Predicate.isString(decoded)) {\n throw new FortnoxEmulatorInputInvalid({ input: 'seed', reason: decoded })\n }\n\n return decoded\n },\n setup: ({ app, state }) =>\n registerFortnoxApi(app, state, env, jobId =>\n jobId === undefined ? false : (jobs.get(jobId)?.() ?? false)\n )\n })\n\n const runtime = await core.createCustomRuntime(definition, { seed: initial })\n\n let baseline: FortnoxEmulatorState = initial\n let entries: Array<MutableLedgerEntry> = []\n let faultStates: Array<MutableFaultState> = []\n let nextSeq = 1\n let nextFaultId = 1\n let closed = false\n\n const snapshotEntry = (entry: MutableLedgerEntry): FortnoxLedgerEntry => ({\n ...entry,\n query: { ...entry.query }\n })\n\n const snapshotFault = (state: MutableFaultState): FortnoxFaultState => ({ ...state })\n\n const clearLedger = () => {\n entries = []\n nextSeq = 1\n }\n\n const addFault = (input: unknown): FortnoxFaultState | string => {\n const decoded = decodeFault(input)\n\n if (Result.isFailure(decoded)) {\n return issueMessage(decoded.failure.issue)\n }\n\n const state: MutableFaultState = {\n id: nextFaultId++,\n fault: decoded.success,\n remaining: decoded.success.count,\n applied: 0\n }\n\n faultStates.push(state)\n\n return snapshotFault(state)\n }\n\n const takeFault = (method: string, path: string): MutableFaultState | undefined =>\n faultStates.find(\n state =>\n (state.remaining === undefined || state.remaining > 0) &&\n faultMatches(state.fault, method, path)\n )\n\n /** Build the fault's response first: a response that cannot be built must not consume it. */\n const applyFault = (state: MutableFaultState): Response => {\n const headers = new Headers(state.fault.headers ?? {})\n const body = state.fault.body ?? defaultFaultBody(state.fault.status)\n\n if (!headers.has('content-type')) {\n headers.set('content-type', Predicate.isString(body) ? 'text/plain' : 'application/json')\n }\n\n const response = new Response(Predicate.isString(body) ? body : JSON.stringify(body), {\n status: state.fault.status,\n headers\n })\n\n state.applied += 1\n\n if (state.remaining !== undefined) {\n state.remaining -= 1\n }\n\n return response\n }\n\n const snapshot = (): FortnoxEmulatorState => runtime.snapshot().state\n\n const restore = (state: FortnoxEmulatorState): Promise<void> => {\n const current: EmulatorSnapshot<FortnoxEmulatorState> = runtime.snapshot()\n\n return runtime.restore({ ...current, state })\n }\n\n const reset = async () => {\n clearLedger()\n faultStates = []\n await restore(baseline)\n }\n\n const reseed = async (input: unknown): Promise<FortnoxEmulatorState | string> => {\n const next = buildSeedState(input)\n\n if (Predicate.isString(next)) {\n return next\n }\n\n await restore(next)\n baseline = next\n\n return next\n }\n\n const coverage = (): FortnoxCoverage => ({\n routes: fortnoxEmulatorRoutes.map(route => ({\n ...route,\n requests: entries.filter(\n entry => entry.route === route.path && entry.method.toUpperCase() === route.method\n ).length\n })),\n unknownRouteRequests: entries.filter(entry => entry.evidence === 'unknown-route').length\n })\n\n /**\n * Authorization, body parsing, then the core route (without the credential), which asks for the\n * fault only once it would answer successfully.\n */\n const routed = async (\n request: Request,\n url: URL,\n entry: MutableLedgerEntry\n ): Promise<Response> => {\n if (!bearerPattern.test(request.headers.get('authorization') ?? '')) {\n return errorInformation(\n 401,\n codes.unauthorized,\n 'Synthetic: missing or invalid authorization.'\n )\n }\n\n const text = await readText(request)\n\n if (text === undefined) {\n return errorInformation(400, codes.invalidBody, 'Synthetic: the request body is unreadable.')\n }\n\n if (text !== '') {\n const json = parseJsonText(text)\n\n if (json === undefined) {\n return errorInformation(\n 400,\n codes.invalidBody,\n 'Synthetic: the request body is not valid JSON.'\n )\n }\n\n entry.body = json\n }\n\n const method = request.method.toUpperCase()\n const hasBody = text !== '' && method !== 'GET' && method !== 'HEAD'\n const jobId = String(nextJobId++)\n\n const headers = new Headers({ accept: 'application/json', [emulatorJobHeader]: jobId })\n\n if (hasBody) headers.set('content-type', 'application/json')\n\n const init: RequestInit = { method, headers }\n\n if (hasBody) {\n init.body = text\n }\n\n const job: FaultJob = {}\n\n // Asked by the route only for an answer it would send successfully, before it commits.\n jobs.set(jobId, () => {\n const fault = takeFault(method, url.pathname)\n\n if (fault === undefined) return false\n\n try {\n job.faultAnswer = applyFault(fault)\n } catch (error) {\n // The fault's answer could not be built (the route did not fail): the core answers its\n // handler failure, and the fault is not used up.\n entry.responseError = 'the emulator could not build or produce the response'\n\n throw error\n }\n\n entry.fault = 'status'\n\n return true\n })\n\n const response = await runtime\n .fetch(new Request(new URL(`${url.pathname}${url.search}`, runtime.baseUrl), init))\n .finally(() => jobs.delete(jobId))\n\n // The fault's answer is sent from here, never through the core.\n if (job.faultAnswer !== undefined) return job.faultAnswer\n\n if (response.headers.has(handlerFailedHeader)) {\n entry.responseError ??= 'the route handler failed'\n\n return responseFailed()\n }\n\n return response\n }\n\n const emulatedApi = async (request: Request, url: URL): Promise<Response> => {\n const route = matchFortnoxRoute(request.method, url.pathname)\n\n const entry: MutableLedgerEntry = {\n seq: nextSeq++,\n method: request.method,\n path: url.pathname,\n query: Object.fromEntries(url.searchParams),\n status: 0,\n evidence: route?.evidence ?? 'unknown-route'\n }\n\n entries.push(entry)\n\n if (route === undefined) {\n entry.status = 404\n\n return errorInformation(404, codes.unknownRoute, 'Synthetic: no emulated Fortnox route.')\n }\n\n entry.route = route.path\n\n // Error recovery still answers through the route: the fallback 500 is evidence-tagged and\n // the ledger records the status actually sent.\n const response = await routed(request, url, entry).catch(() => {\n entry.responseError = 'the emulator could not build or produce the response'\n\n return responseFailed()\n })\n\n const tagged = withEvidence(response, route.evidence)\n\n entry.status = tagged.status\n\n return tagged\n }\n\n const controlPlane = async (request: Request, path: string): Promise<Response> => {\n const method = request.method\n const allow = (methods: string) => controlError(405, 'method not allowed', { allow: methods })\n\n const jsonBody = async (): Promise<Schema.Json | undefined> => {\n const text = await readText(request)\n\n return text === undefined ? undefined : parseJsonText(text)\n }\n\n switch (path) {\n case '/_emulate/ledger':\n if (method === 'GET') {\n return jsonResponse(200, { entries: entries.map(snapshotEntry) })\n }\n\n if (method === 'DELETE') {\n const cleared = entries.length\n\n clearLedger()\n\n return jsonResponse(200, { cleared })\n }\n\n return allow('GET, DELETE')\n\n case '/_emulate/faults': {\n if (method === 'GET') {\n return jsonResponse(200, { faults: faultStates.map(snapshotFault) })\n }\n\n if (method === 'DELETE') {\n const cleared = faultStates.length\n\n faultStates = []\n\n return jsonResponse(200, { cleared })\n }\n\n if (method !== 'POST') {\n return allow('GET, POST, DELETE')\n }\n\n const decoded = decodeFaultList(await jsonBody())\n\n if (Result.isFailure(decoded)) {\n return controlError(400, `invalid fault: ${issueMessage(decoded.failure.issue)}`)\n }\n\n const faults = 'faults' in decoded.success ? decoded.success.faults : [decoded.success]\n\n return jsonResponse(201, { faults: faults.map(fault => addFault(fault)) })\n }\n\n case '/_emulate/reset':\n if (method !== 'POST') {\n return allow('POST')\n }\n\n await reset()\n\n return jsonResponse(200, { reset: true })\n\n case '/_emulate/state':\n if (method !== 'GET') {\n return allow('GET')\n }\n\n return jsonResponse(200, {\n state: snapshot(),\n faults: faultStates.map(snapshotFault),\n ledgerEntries: entries.length\n })\n\n case '/_emulate/seed': {\n if (method !== 'POST') {\n return allow('POST')\n }\n\n const next = await reseed((await jsonBody()) ?? null)\n\n if (Predicate.isString(next)) {\n return controlError(400, `invalid seed: ${next}`)\n }\n\n return jsonResponse(200, {\n seeded: true,\n customers: next.customers.length,\n invoices: next.invoices.length\n })\n }\n\n case '/_emulate/coverage':\n if (method !== 'GET') {\n return allow('GET')\n }\n\n return jsonResponse(200, coverage())\n\n default:\n return controlError(404, 'unknown control-plane route')\n }\n }\n\n /**\n * Last resort when handling itself fails (for example an unparseable request URL): API\n * requests answer a Fortnox `ErrorInformation` 500, tagged with the matched route's evidence;\n * control-plane requests answer an emulator error.\n */\n const lastResort = (request: Request): Response => {\n const path = URL.canParse(request.url) ? new URL(request.url).pathname : undefined\n\n if (path !== undefined && isControlPath(path)) {\n return controlError(500, 'emulator failed to handle the request')\n }\n\n const route = path === undefined ? undefined : matchFortnoxRoute(request.method, path)\n\n return route === undefined ? responseFailed() : withEvidence(responseFailed(), route.evidence)\n }\n\n const handle = async (request: Request): Promise<Response> => {\n if (closed) {\n return errorInformation(503, codes.upstreamError, 'Synthetic: the emulator is closed.')\n }\n\n const url = new URL(request.url)\n\n return isControlPath(url.pathname)\n ? controlPlane(request, url.pathname)\n : emulatedApi(request, url)\n }\n\n return {\n fetch: request => handle(request).catch(() => lastResort(request)),\n baseUrl: linkOrigin,\n ledger: {\n entries: () => entries.map(snapshotEntry),\n clear: clearLedger\n },\n faults: {\n add: fault => {\n const added = addFault(fault)\n\n if (Predicate.isString(added)) {\n throw new FortnoxEmulatorInputInvalid({ input: 'fault', reason: added })\n }\n\n return added\n },\n list: () => faultStates.map(snapshotFault),\n clear: () => {\n faultStates = []\n }\n },\n reset,\n seed: async input => {\n const next = await reseed(input)\n\n if (Predicate.isString(next)) {\n throw new FortnoxEmulatorInputInvalid({ input: 'seed', reason: next })\n }\n },\n snapshot,\n coverage,\n close: () => {\n closed = true\n\n return runtime.close()\n }\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { FixtureRecording } from "./fixture-route.mjs";
2
+
3
+ //#region src/gateway-evaluate-recordings.d.ts
4
+ declare const gatewayEvaluateBooleanRecording: FixtureRecording;
5
+ declare const gatewayEvaluateChoiceRecording: FixtureRecording;
6
+ declare const gatewayEvaluateScoreRecording: FixtureRecording;
7
+ declare const gatewayEvaluateErrorEnvelopeRecording: FixtureRecording;
8
+ /** Every classifier recording, in conformance case order. */
9
+ declare const gatewayEvaluateRecordings: ReadonlyArray<FixtureRecording>;
10
+ //#endregion
11
+ export { gatewayEvaluateBooleanRecording, gatewayEvaluateChoiceRecording, gatewayEvaluateErrorEnvelopeRecording, gatewayEvaluateRecordings, gatewayEvaluateScoreRecording };
12
+ //# sourceMappingURL=gateway-evaluate-recordings.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gateway-evaluate-recordings.d.mts","names":[],"sources":["../src/gateway-evaluate-recordings.ts"],"mappings":";;;cAkCa,+BAAA,EAAiC,gBAkB7C;AAAA,cAEY,8BAAA,EAAgC,gBAmC5C;AAAA,cAEY,6BAAA,EAA+B,gBAiC3C;AAAA,cAEY,qCAAA,EAAuC,gBAkBnD;AArDD;AAAA,cAwDa,yBAAA,EAA2B,aAAa,CAAC,gBAAA"}
@@ -0,0 +1,128 @@
1
+ //#region src/gateway-evaluate-recordings.ts
2
+ const approvalRequestBody = (model) => ({
3
+ model,
4
+ state: "Synthetic reply: thanks, the fix works on my side.",
5
+ questions: { approves: {
6
+ type: "boolean",
7
+ instructions: "Does the reply approve the delivered result?",
8
+ criteria: {
9
+ true: "The reply accepts or approves the result.",
10
+ false: "The reply rejects or questions the result."
11
+ }
12
+ } }
13
+ });
14
+ const jsonHeaders = {
15
+ accept: "application/json",
16
+ "content-type": "application/json"
17
+ };
18
+ const jsonResponseHeaders = { "content-type": "application/json" };
19
+ const gatewayEvaluateBooleanRecording = {
20
+ fixtureId: "vercel-ai-gateway.classify.boolean.synthetic",
21
+ caseId: "vercel-ai-gateway.classify.boolean",
22
+ request: {
23
+ method: "POST",
24
+ path: "/v1/evaluate",
25
+ query: "",
26
+ headers: jsonHeaders,
27
+ body: approvalRequestBody("typesafe-ai/jev")
28
+ },
29
+ response: {
30
+ status: 200,
31
+ headers: jsonResponseHeaders,
32
+ streamed: false,
33
+ chunks: ["{\"model\":\"typesafe-ai/jev\",\"answers\":{\"approves\":{\"type\":\"boolean\",\"probability\":0.93}},\"usage\":{\"inputTokens\":58,\"outputTokens\":0},\"providerMetadata\":{\"gateway\":{\"cost\":\"0.000002436\"}}}"]
34
+ }
35
+ };
36
+ const gatewayEvaluateChoiceRecording = {
37
+ fixtureId: "vercel-ai-gateway.classify.choice.synthetic",
38
+ caseId: "vercel-ai-gateway.classify.choice",
39
+ request: {
40
+ method: "POST",
41
+ path: "/v1/evaluate",
42
+ query: "",
43
+ headers: jsonHeaders,
44
+ body: {
45
+ model: "typesafe-ai/jev",
46
+ state: {
47
+ subject: "Synthetic invoice question",
48
+ body: "I was charged twice for the synthetic plan."
49
+ },
50
+ questions: { route: {
51
+ type: "choice",
52
+ instructions: "Which team should handle this ticket?",
53
+ criteria: {
54
+ billing: "Payments, invoices, and refunds.",
55
+ bug: "Product defects and errors.",
56
+ other: "Anything else."
57
+ }
58
+ } }
59
+ }
60
+ },
61
+ response: {
62
+ status: 200,
63
+ headers: jsonResponseHeaders,
64
+ streamed: false,
65
+ chunks: ["{\"model\":\"typesafe-ai/jev\",\"answers\":{\"route\":{\"type\":\"choice\",\"choice\":\"billing\",\"probabilities\":{\"billing\":0.91,\"bug\":0.06,\"other\":0.03}}},\"usage\":{\"inputTokens\":74,\"outputTokens\":0},\"providerMetadata\":{\"gateway\":{\"cost\":\"0.000003108\"},\"typesafe\":{\"confidence\":{\"route\":0.88}}}}"]
66
+ }
67
+ };
68
+ const gatewayEvaluateScoreRecording = {
69
+ fixtureId: "vercel-ai-gateway.classify.score.synthetic",
70
+ caseId: "vercel-ai-gateway.classify.score",
71
+ request: {
72
+ method: "POST",
73
+ path: "/v1/evaluate",
74
+ query: "",
75
+ headers: jsonHeaders,
76
+ body: {
77
+ model: "typesafe-ai/jev",
78
+ state: [{
79
+ author: "synthetic-user",
80
+ text: "The synthetic dashboard is down for everyone."
81
+ }],
82
+ questions: { urgency: {
83
+ type: "score",
84
+ instructions: "How urgent is this report?",
85
+ criteria: [
86
+ "Not urgent.",
87
+ "Somewhat urgent.",
88
+ "Urgent.",
89
+ "Critical outage."
90
+ ]
91
+ } }
92
+ }
93
+ },
94
+ response: {
95
+ status: 200,
96
+ headers: jsonResponseHeaders,
97
+ streamed: false,
98
+ chunks: ["{\"model\":\"typesafe-ai/jev\",\"answers\":{\"urgency\":{\"type\":\"score\",\"score\":2.74,\"probabilities\":{\"0\":0.01,\"1\":0.04,\"2\":0.15,\"3\":0.8},\"confidence\":0.77}},\"usage\":{\"inputTokens\":66,\"outputTokens\":0},\"providerMetadata\":{\"gateway\":{\"cost\":\"0.000002772\"}}}"]
99
+ }
100
+ };
101
+ const gatewayEvaluateErrorEnvelopeRecording = {
102
+ fixtureId: "vercel-ai-gateway.classify.error-envelope.synthetic",
103
+ caseId: "vercel-ai-gateway.classify.error-envelope",
104
+ request: {
105
+ method: "POST",
106
+ path: "/v1/evaluate",
107
+ query: "",
108
+ headers: jsonHeaders,
109
+ body: approvalRequestBody("yolk-conformance/model-does-not-exist")
110
+ },
111
+ response: {
112
+ status: 404,
113
+ headers: jsonResponseHeaders,
114
+ streamed: false,
115
+ chunks: ["{\"message\":\"Model 'yolk-conformance/model-does-not-exist' not found\",\"error_type\":\"model_not_found\"}"]
116
+ }
117
+ };
118
+ /** Every classifier recording, in conformance case order. */
119
+ const gatewayEvaluateRecordings = [
120
+ gatewayEvaluateBooleanRecording,
121
+ gatewayEvaluateChoiceRecording,
122
+ gatewayEvaluateScoreRecording,
123
+ gatewayEvaluateErrorEnvelopeRecording
124
+ ];
125
+ //#endregion
126
+ export { gatewayEvaluateBooleanRecording, gatewayEvaluateChoiceRecording, gatewayEvaluateErrorEnvelopeRecording, gatewayEvaluateRecordings, gatewayEvaluateScoreRecording };
127
+
128
+ //# sourceMappingURL=gateway-evaluate-recordings.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gateway-evaluate-recordings.mjs","names":[],"sources":["../src/gateway-evaluate-recordings.ts"],"sourcesContent":["/**\n * AI Gateway classifier (`POST /v1/evaluate`) recordings the `/gateway` evaluate route answers\n * from.\n *\n * Copied as data from the committed (synthetic, unverified) classifier conformance fixtures; never\n * imported. `test/fixture-recordings.test.ts` fails when a fixture changes and this copy does not.\n * Internal; not a package export.\n */\nimport type { FixtureRecording } from './fixture-route.ts'\n\nconst approvalRequestBody = (model: string) => ({\n model,\n state: 'Synthetic reply: thanks, the fix works on my side.',\n questions: {\n approves: {\n type: 'boolean',\n instructions: 'Does the reply approve the delivered result?',\n criteria: {\n true: 'The reply accepts or approves the result.',\n false: 'The reply rejects or questions the result.'\n }\n }\n }\n})\n\nconst jsonHeaders = {\n accept: 'application/json',\n 'content-type': 'application/json'\n}\n\nconst jsonResponseHeaders = {\n 'content-type': 'application/json'\n}\n\nexport const gatewayEvaluateBooleanRecording: FixtureRecording = {\n fixtureId: 'vercel-ai-gateway.classify.boolean.synthetic',\n caseId: 'vercel-ai-gateway.classify.boolean',\n request: {\n method: 'POST',\n path: '/v1/evaluate',\n query: '',\n headers: jsonHeaders,\n body: approvalRequestBody('typesafe-ai/jev')\n },\n response: {\n status: 200,\n headers: jsonResponseHeaders,\n streamed: false,\n chunks: [\n '{\"model\":\"typesafe-ai/jev\",\"answers\":{\"approves\":{\"type\":\"boolean\",\"probability\":0.93}},\"usage\":{\"inputTokens\":58,\"outputTokens\":0},\"providerMetadata\":{\"gateway\":{\"cost\":\"0.000002436\"}}}'\n ]\n }\n}\n\nexport const gatewayEvaluateChoiceRecording: FixtureRecording = {\n fixtureId: 'vercel-ai-gateway.classify.choice.synthetic',\n caseId: 'vercel-ai-gateway.classify.choice',\n request: {\n method: 'POST',\n path: '/v1/evaluate',\n query: '',\n headers: jsonHeaders,\n body: {\n model: 'typesafe-ai/jev',\n state: {\n subject: 'Synthetic invoice question',\n body: 'I was charged twice for the synthetic plan.'\n },\n questions: {\n route: {\n type: 'choice',\n instructions: 'Which team should handle this ticket?',\n criteria: {\n billing: 'Payments, invoices, and refunds.',\n bug: 'Product defects and errors.',\n other: 'Anything else.'\n }\n }\n }\n }\n },\n response: {\n status: 200,\n headers: jsonResponseHeaders,\n streamed: false,\n chunks: [\n '{\"model\":\"typesafe-ai/jev\",\"answers\":{\"route\":{\"type\":\"choice\",\"choice\":\"billing\",\"probabilities\":{\"billing\":0.91,\"bug\":0.06,\"other\":0.03}}},\"usage\":{\"inputTokens\":74,\"outputTokens\":0},\"providerMetadata\":{\"gateway\":{\"cost\":\"0.000003108\"},\"typesafe\":{\"confidence\":{\"route\":0.88}}}}'\n ]\n }\n}\n\nexport const gatewayEvaluateScoreRecording: FixtureRecording = {\n fixtureId: 'vercel-ai-gateway.classify.score.synthetic',\n caseId: 'vercel-ai-gateway.classify.score',\n request: {\n method: 'POST',\n path: '/v1/evaluate',\n query: '',\n headers: jsonHeaders,\n body: {\n model: 'typesafe-ai/jev',\n state: [\n {\n author: 'synthetic-user',\n text: 'The synthetic dashboard is down for everyone.'\n }\n ],\n questions: {\n urgency: {\n type: 'score',\n instructions: 'How urgent is this report?',\n criteria: ['Not urgent.', 'Somewhat urgent.', 'Urgent.', 'Critical outage.']\n }\n }\n }\n },\n response: {\n status: 200,\n headers: jsonResponseHeaders,\n streamed: false,\n chunks: [\n '{\"model\":\"typesafe-ai/jev\",\"answers\":{\"urgency\":{\"type\":\"score\",\"score\":2.74,\"probabilities\":{\"0\":0.01,\"1\":0.04,\"2\":0.15,\"3\":0.8},\"confidence\":0.77}},\"usage\":{\"inputTokens\":66,\"outputTokens\":0},\"providerMetadata\":{\"gateway\":{\"cost\":\"0.000002772\"}}}'\n ]\n }\n}\n\nexport const gatewayEvaluateErrorEnvelopeRecording: FixtureRecording = {\n fixtureId: 'vercel-ai-gateway.classify.error-envelope.synthetic',\n caseId: 'vercel-ai-gateway.classify.error-envelope',\n request: {\n method: 'POST',\n path: '/v1/evaluate',\n query: '',\n headers: jsonHeaders,\n body: approvalRequestBody('yolk-conformance/model-does-not-exist')\n },\n response: {\n status: 404,\n headers: jsonResponseHeaders,\n streamed: false,\n chunks: [\n '{\"message\":\"Model \\'yolk-conformance/model-does-not-exist\\' not found\",\"error_type\":\"model_not_found\"}'\n ]\n }\n}\n\n/** Every classifier recording, in conformance case order. */\nexport const gatewayEvaluateRecordings: ReadonlyArray<FixtureRecording> = [\n gatewayEvaluateBooleanRecording,\n gatewayEvaluateChoiceRecording,\n gatewayEvaluateScoreRecording,\n gatewayEvaluateErrorEnvelopeRecording\n]\n"],"mappings":";AAUA,MAAM,uBAAuB,WAAmB;CAC9C;CACA,OAAO;CACP,WAAW,EACT,UAAU;EACR,MAAM;EACN,cAAc;EACd,UAAU;GACR,MAAM;GACN,OAAO;EACT;CACF,EACF;AACF;AAEA,MAAM,cAAc;CAClB,QAAQ;CACR,gBAAgB;AAClB;AAEA,MAAM,sBAAsB,EAC1B,gBAAgB,mBAClB;AAEA,MAAa,kCAAoD;CAC/D,WAAW;CACX,QAAQ;CACR,SAAS;EACP,QAAQ;EACR,MAAM;EACN,OAAO;EACP,SAAS;EACT,MAAM,oBAAoB,iBAAiB;CAC7C;CACA,UAAU;EACR,QAAQ;EACR,SAAS;EACT,UAAU;EACV,QAAQ,CACN,wNACF;CACF;AACF;AAEA,MAAa,iCAAmD;CAC9D,WAAW;CACX,QAAQ;CACR,SAAS;EACP,QAAQ;EACR,MAAM;EACN,OAAO;EACP,SAAS;EACT,MAAM;GACJ,OAAO;GACP,OAAO;IACL,SAAS;IACT,MAAM;GACR;GACA,WAAW,EACT,OAAO;IACL,MAAM;IACN,cAAc;IACd,UAAU;KACR,SAAS;KACT,KAAK;KACL,OAAO;IACT;GACF,EACF;EACF;CACF;CACA,UAAU;EACR,QAAQ;EACR,SAAS;EACT,UAAU;EACV,QAAQ,CACN,sUACF;CACF;AACF;AAEA,MAAa,gCAAkD;CAC7D,WAAW;CACX,QAAQ;CACR,SAAS;EACP,QAAQ;EACR,MAAM;EACN,OAAO;EACP,SAAS;EACT,MAAM;GACJ,OAAO;GACP,OAAO,CACL;IACE,QAAQ;IACR,MAAM;GACR,CACF;GACA,WAAW,EACT,SAAS;IACP,MAAM;IACN,cAAc;IACd,UAAU;KAAC;KAAe;KAAoB;KAAW;IAAkB;GAC7E,EACF;EACF;CACF;CACA,UAAU;EACR,QAAQ;EACR,SAAS;EACT,UAAU;EACV,QAAQ,CACN,kSACF;CACF;AACF;AAEA,MAAa,wCAA0D;CACrE,WAAW;CACX,QAAQ;CACR,SAAS;EACP,QAAQ;EACR,MAAM;EACN,OAAO;EACP,SAAS;EACT,MAAM,oBAAoB,uCAAuC;CACnE;CACA,UAAU;EACR,QAAQ;EACR,SAAS;EACT,UAAU;EACV,QAAQ,CACN,8GACF;CACF;AACF;;AAGA,MAAa,4BAA6D;CACxE;CACA;CACA;CACA;AACF"}
@@ -0,0 +1,272 @@
1
+ import { EmulatorEvidence, EmulatorRouteEvidence, emulatorEvidenceHeader } from "./route-evidence.mjs";
2
+ import { FixtureRouteEmulator, FixtureRouteFault, FixtureRouteFaultKind, FixtureRouteLedgerEntry, FixtureRouteScriptedTurn } from "./fixture-route.mjs";
3
+ import { ChatCompletionsEmulator, ChatCoverage, ChatFault, ChatFaultKind, ChatFaultMatch, ChatFaultState, ChatLedgerEntry, ChatRouteCoverage, ChatScriptedError, ChatScriptedReasoningCompletion, ChatScriptedReasoningTurn, ChatScriptedToolCall, ChatScriptedUsage } from "./chat-completions.mjs";
4
+ import * as Schema from "effect/Schema";
5
+
6
+ //#region src/gateway.d.ts
7
+ declare const gatewayChatCompletionsPath = "/v1/chat/completions";
8
+ /** The AI Gateway classifier ("evaluation") path. */
9
+ declare const gatewayEvaluatePath = "/v1/evaluate";
10
+ /** Synthetic-safe default model ids, including the Gateway conformance defaults. */
11
+ declare const gatewayEmulatorDefaultModels: ReadonlyArray<string>;
12
+ /** Models that stream reasoning deltas when reasoning is requested. */
13
+ declare const gatewayEmulatorDefaultReasoningModels: ReadonlyArray<string>;
14
+ /**
15
+ * SSE events per network chunk by default. The live Gateway packs several
16
+ * events into one network chunk (the recordings carry one to four, always
17
+ * with the finish event and `data: [DONE]` together in the last chunk).
18
+ */
19
+ declare const gatewayEmulatorDefaultEventsPerChunk = 2;
20
+ /**
21
+ * Route evidence manifest: every emulated Gateway route and the conformance
22
+ * cases whose verified live recordings (2026-09-30) its wire shapes follow.
23
+ */
24
+ declare const gatewayEmulatorRoutes: ReadonlyArray<EmulatorRouteEvidence>;
25
+ /**
26
+ * Route evidence manifest of the classifier route (served by the same fetch handler, with its own
27
+ * ledger, faults, and coverage). Its recordings are synthetic placeholders, so it is unverified.
28
+ */
29
+ declare const gatewayEvaluateEmulatorRoutes: ReadonlyArray<EmulatorRouteEvidence>;
30
+ /** Optional fault filter; an omitted field matches every request. `path` ending in `*` is a prefix. */
31
+ declare const GatewayFaultMatch: Schema.Struct<{
32
+ readonly path: Schema.optionalKey<Schema.String>;
33
+ readonly model: Schema.optionalKey<Schema.String>;
34
+ }>;
35
+ type GatewayFaultMatch = ChatFaultMatch;
36
+ /**
37
+ * Wire faults for emulated routes:
38
+ *
39
+ * - `status`: answer with this status, headers, and body instead of a
40
+ * completion (for example 429 with `retry-after`). The body defaults to a
41
+ * Gateway error envelope. Statuses that cannot carry a body (1xx, 204, 205,
42
+ * 304) and redirects (3xx) are rejected, as are invalid header names or
43
+ * values and a `location` header; scripted errors follow the same rules.
44
+ * - `error-after-chunks`: send `chunks` body chunks, then error the body
45
+ * stream (a dropped connection).
46
+ * - `truncate-after-chunks`: send `chunks` body chunks, then close the body
47
+ * cleanly (for example without `data: [DONE]`).
48
+ *
49
+ * Chunk faults count network chunks: a streamed chunk carries up to
50
+ * `eventsPerChunk` SSE events (default 2), and a whole JSON body counts as one
51
+ * chunk. A chunk fault that cannot take effect (`error-after-chunks` beyond
52
+ * the chunk count, or `truncate-after-chunks` at or beyond it) answers 500
53
+ * with an emulator error instead of silently doing nothing, and is not
54
+ * consumed.
55
+ */
56
+ declare const GatewayFault: Schema.Union<readonly [Schema.Struct<{
57
+ readonly match: Schema.optionalKey<Schema.Struct<{
58
+ readonly path: Schema.optionalKey<Schema.String>;
59
+ readonly model: Schema.optionalKey<Schema.String>;
60
+ }>>;
61
+ readonly count: Schema.optionalKey<Schema.Int>;
62
+ readonly kind: Schema.Literal<"status">;
63
+ readonly status: Schema.Int;
64
+ readonly headers: Schema.optionalKey<Schema.$Record<Schema.String, Schema.String>>;
65
+ readonly body: Schema.optionalKey<Schema.Codec<Schema.Json, Schema.Json, never, never>>;
66
+ }>, Schema.Struct<{
67
+ readonly match: Schema.optionalKey<Schema.Struct<{
68
+ readonly path: Schema.optionalKey<Schema.String>;
69
+ readonly model: Schema.optionalKey<Schema.String>;
70
+ }>>;
71
+ readonly count: Schema.optionalKey<Schema.Int>;
72
+ readonly kind: Schema.Literal<"error-after-chunks">;
73
+ readonly chunks: Schema.Int;
74
+ }>, Schema.Struct<{
75
+ readonly match: Schema.optionalKey<Schema.Struct<{
76
+ readonly path: Schema.optionalKey<Schema.String>;
77
+ readonly model: Schema.optionalKey<Schema.String>;
78
+ }>>;
79
+ readonly count: Schema.optionalKey<Schema.Int>;
80
+ readonly kind: Schema.Literal<"truncate-after-chunks">;
81
+ readonly chunks: Schema.Int;
82
+ }>]>;
83
+ type GatewayFault = ChatFault;
84
+ type GatewayFaultKind = ChatFaultKind;
85
+ /**
86
+ * Usage for a scripted turn, sent as the Gateway `usage` object (token counts,
87
+ * `completion_tokens_details.reasoning_tokens` defaulting to 0, and synthetic
88
+ * zero costs).
89
+ */
90
+ declare const GatewayScriptedUsage: Schema.Struct<{
91
+ readonly promptTokens: Schema.Int;
92
+ readonly completionTokens: Schema.Int;
93
+ readonly reasoningTokens: Schema.optionalKey<Schema.Int>;
94
+ }>;
95
+ type GatewayScriptedUsage = ChatScriptedUsage;
96
+ /** One scripted tool call; its JSON arguments stream as these fragments. */
97
+ declare const GatewayScriptedToolCall: Schema.Struct<{
98
+ readonly name: Schema.NonEmptyString;
99
+ readonly argumentFragments: Schema.$Array<Schema.String>;
100
+ readonly id: Schema.optionalKey<Schema.NonEmptyString>;
101
+ }>;
102
+ type GatewayScriptedToolCall = ChatScriptedToolCall;
103
+ /**
104
+ * A scripted completion. Every field is exact (nothing is filled in) except:
105
+ * `usage` omitted is synthesized when the request asks for usage, and `null`
106
+ * drops it; `finishReason` omitted is `tool_calls` with tool calls, else
107
+ * `stop`. `order` defaults to `reasoning-first`; `reasoningField` defaults to
108
+ * `reasoning` (streamed with `reasoning_details`, as recorded live); the
109
+ * DeepSeek-native `reasoning_content` is sent alone.
110
+ */
111
+ declare const GatewayScriptedCompletion: Schema.Struct<{
112
+ readonly text: Schema.optionalKey<Schema.$Array<Schema.String>>;
113
+ readonly reasoning: Schema.optionalKey<Schema.$Array<Schema.String>>;
114
+ readonly reasoningField: Schema.optionalKey<Schema.Literals<readonly ["reasoning_content", "reasoning"]>>;
115
+ readonly order: Schema.optionalKey<Schema.Literals<readonly ["reasoning-first", "text-first"]>>;
116
+ readonly toolCalls: Schema.optionalKey<Schema.$Array<Schema.Struct<{
117
+ readonly name: Schema.NonEmptyString;
118
+ readonly argumentFragments: Schema.$Array<Schema.String>;
119
+ readonly id: Schema.optionalKey<Schema.NonEmptyString>;
120
+ }>>>;
121
+ readonly usage: Schema.optionalKey<Schema.NullOr<Schema.Struct<{
122
+ readonly promptTokens: Schema.Int;
123
+ readonly completionTokens: Schema.Int;
124
+ readonly reasoningTokens: Schema.optionalKey<Schema.Int>;
125
+ }>>>;
126
+ readonly finishReason: Schema.optionalKey<Schema.NonEmptyString>;
127
+ }>;
128
+ type GatewayScriptedCompletion = ChatScriptedReasoningCompletion;
129
+ /** A scripted error response: status, body (a string is sent as is), and optional headers. */
130
+ declare const GatewayScriptedError: Schema.Struct<{
131
+ readonly error: Schema.Struct<{
132
+ readonly status: Schema.Int;
133
+ readonly body: Schema.Codec<Schema.Json, Schema.Json, never, never>;
134
+ readonly headers: Schema.optionalKey<Schema.$Record<Schema.String, Schema.String>>;
135
+ }>;
136
+ }>;
137
+ type GatewayScriptedError = ChatScriptedError;
138
+ /** A turn queued for the next chat completion request. */
139
+ declare const GatewayScriptedTurn: Schema.Union<readonly [Schema.Struct<{
140
+ readonly error: Schema.Struct<{
141
+ readonly status: Schema.Int;
142
+ readonly body: Schema.Codec<Schema.Json, Schema.Json, never, never>;
143
+ readonly headers: Schema.optionalKey<Schema.$Record<Schema.String, Schema.String>>;
144
+ }>;
145
+ }>, Schema.Struct<{
146
+ readonly text: Schema.optionalKey<Schema.$Array<Schema.String>>;
147
+ readonly reasoning: Schema.optionalKey<Schema.$Array<Schema.String>>;
148
+ readonly reasoningField: Schema.optionalKey<Schema.Literals<readonly ["reasoning_content", "reasoning"]>>;
149
+ readonly order: Schema.optionalKey<Schema.Literals<readonly ["reasoning-first", "text-first"]>>;
150
+ readonly toolCalls: Schema.optionalKey<Schema.$Array<Schema.Struct<{
151
+ readonly name: Schema.NonEmptyString;
152
+ readonly argumentFragments: Schema.$Array<Schema.String>;
153
+ readonly id: Schema.optionalKey<Schema.NonEmptyString>;
154
+ }>>>;
155
+ readonly usage: Schema.optionalKey<Schema.NullOr<Schema.Struct<{
156
+ readonly promptTokens: Schema.Int;
157
+ readonly completionTokens: Schema.Int;
158
+ readonly reasoningTokens: Schema.optionalKey<Schema.Int>;
159
+ }>>>;
160
+ readonly finishReason: Schema.optionalKey<Schema.NonEmptyString>;
161
+ }>]>;
162
+ type GatewayScriptedTurn = ChatScriptedReasoningTurn;
163
+ declare const GatewayEmulatorInputInvalid_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }>) => import("effect/Cause").YieldableError & {
164
+ readonly _tag: "GatewayEmulatorInputInvalid";
165
+ } & Readonly<A>;
166
+ /**
167
+ * Thrown by the JS API (`faults.add`, `script.enqueue`) for invalid input, and
168
+ * by `makeGatewayEmulator` for invalid options; a programmer error.
169
+ */
170
+ declare class GatewayEmulatorInputInvalid extends GatewayEmulatorInputInvalid_base<{
171
+ readonly input: 'fault' | 'turn' | 'options';
172
+ readonly reason: string;
173
+ }> {
174
+ get message(): string;
175
+ }
176
+ type GatewayLedgerEntry = ChatLedgerEntry;
177
+ type GatewayFaultState = ChatFaultState;
178
+ type GatewayRouteCoverage = ChatRouteCoverage;
179
+ type GatewayCoverage = ChatCoverage;
180
+ type GatewayEmulatorOptions = {
181
+ /** Model ids that exist. Defaults to `gatewayEmulatorDefaultModels`. */readonly knownModels?: ReadonlyArray<string>; /** Model ids that stream reasoning. Defaults to `gatewayEmulatorDefaultReasoningModels`. */
182
+ readonly reasoningModels?: ReadonlyArray<string>;
183
+ /**
184
+ * SSE events per network chunk of a streamed body, a positive integer.
185
+ * Defaults to `gatewayEmulatorDefaultEventsPerChunk` (2); 1 sends one event
186
+ * per chunk. Events are packed counting from the end, so the last chunk
187
+ * holds the finish event and `data: [DONE]` together. Chunk faults count
188
+ * these network chunks.
189
+ */
190
+ readonly eventsPerChunk?: number;
191
+ };
192
+ /** A classifier-route fault (`status` 400-599, `error-after-chunks`, `truncate-after-chunks`). */
193
+ declare const GatewayEvaluateFault: Schema.Union<readonly [Schema.Struct<{
194
+ readonly status: Schema.Int;
195
+ readonly match: Schema.optionalKey<Schema.Struct<{
196
+ readonly path: Schema.optionalKey<Schema.String>;
197
+ readonly model: Schema.optionalKey<Schema.String>;
198
+ }>>;
199
+ readonly count: Schema.optionalKey<Schema.Int>;
200
+ readonly kind: Schema.Literal<"status">;
201
+ readonly headers: Schema.optionalKey<Schema.$Record<Schema.String, Schema.String>>;
202
+ readonly body: Schema.optionalKey<Schema.Codec<Schema.Json, Schema.Json, never, never>>;
203
+ }>, Schema.Struct<{
204
+ readonly match: Schema.optionalKey<Schema.Struct<{
205
+ readonly path: Schema.optionalKey<Schema.String>;
206
+ readonly model: Schema.optionalKey<Schema.String>;
207
+ }>>;
208
+ readonly count: Schema.optionalKey<Schema.Int>;
209
+ readonly kind: Schema.Literal<"error-after-chunks">;
210
+ readonly chunks: Schema.Int;
211
+ }>, Schema.Struct<{
212
+ readonly match: Schema.optionalKey<Schema.Struct<{
213
+ readonly path: Schema.optionalKey<Schema.String>;
214
+ readonly model: Schema.optionalKey<Schema.String>;
215
+ }>>;
216
+ readonly count: Schema.optionalKey<Schema.Int>;
217
+ readonly kind: Schema.Literal<"truncate-after-chunks">;
218
+ readonly chunks: Schema.Int;
219
+ }>]>;
220
+ type GatewayEvaluateFault = FixtureRouteFault;
221
+ type GatewayEvaluateFaultKind = FixtureRouteFaultKind;
222
+ /** A classifier-route turn: a scripted error (status 400-599) only. */
223
+ type GatewayEvaluateScriptedTurn = FixtureRouteScriptedTurn;
224
+ type GatewayEvaluateLedgerEntry = FixtureRouteLedgerEntry;
225
+ type GatewayEvaluateEmulator = FixtureRouteEmulator;
226
+ /** The chat emulator, plus `evaluate`: the classifier route's own emulator API. */
227
+ type GatewayEmulator = ChatCompletionsEmulator<GatewayScriptedTurn> & {
228
+ readonly evaluate: GatewayEvaluateEmulator;
229
+ };
230
+ /**
231
+ * Create a Vercel AI Gateway emulator. Each call has independent ledger,
232
+ * fault, and script state. Throws `GatewayEmulatorInputInvalid` for an
233
+ * invalid `eventsPerChunk`.
234
+ *
235
+ * Without a script, `POST /v1/chat/completions` answers a known model with
236
+ * synthetic text deltas. `stream: true` sends `chat.completion.chunk` SSE in
237
+ * the recorded Gateway shape: a `{ role: 'assistant' }` opening delta, content
238
+ * deltas, and a finish event whose delta carries `provider_metadata` and which
239
+ * carries `usage` (when `stream_options.include_usage` is set),
240
+ * `system_fingerprint`, `service_tier` (for `openai/*` models), and
241
+ * `generationId`, then `data: [DONE]`; every chunk carries
242
+ * `system_fingerprint` and `logprobs: null`, and events are packed
243
+ * `eventsPerChunk` per network chunk. `stream: false` answers one
244
+ * `chat.completion` JSON body. Reasoning models asked for reasoning
245
+ * (`reasoning_effort`, or `thinking.type: 'enabled'`) stream
246
+ * `delta.reasoning` with `delta.reasoning_details` before the text. A request
247
+ * with `tools` gets one tool call whose arguments are synthesized from the
248
+ * tool's JSON Schema and streamed in fragments, finishing with `tool_calls`.
249
+ * Unknown models get the recorded 404 envelope (`type: 'model_not_found'`,
250
+ * `param: { modelId }`, no `code`); a missing bearer credential gets a 401
251
+ * envelope; unknown routes get a 404 JSON error. The ledger records the
252
+ * `max_tokens` limit as `maxCompletionTokens`.
253
+ *
254
+ * Precedence per chat request: authentication and JSON validation, then the
255
+ * first matching fault if it is a `status` fault, then the next scripted
256
+ * turn, then model validation and defaults; a first matching chunk fault then
257
+ * shapes the body. Only the first matching fault (in insertion order) applies. Credential headers are never
258
+ * recorded, and the bearer value is never checked or stored.
259
+ *
260
+ * `POST /v1/evaluate` is fixture-only: a request with a non-empty bearer credential (never checked
261
+ * or stored), the recorded `accept` and `content-type`, no query, and a body matching one of the
262
+ * four classifier recordings (the discriminators `model` and `type` exact; any other string; the
263
+ * same keys, so the recorded question ids, option keys, and level count) gets the recorded
264
+ * response; anything else (another model, `providerOptions`, other questions) answers 400
265
+ * not-emulated. Its ledger, faults (statuses 400-599), scripted errors, and coverage are
266
+ * `emulator.evaluate` (control plane `/_emulate/evaluate/*`); `emulator.faults` and the other
267
+ * top-level APIs stay the chat route's. `reset()` and `POST /_emulate/reset` reset both.
268
+ */
269
+ declare const makeGatewayEmulator: (options?: GatewayEmulatorOptions) => GatewayEmulator;
270
+ //#endregion
271
+ export { type EmulatorEvidence, type EmulatorRouteEvidence, GatewayCoverage, GatewayEmulator, GatewayEmulatorInputInvalid, GatewayEmulatorOptions, GatewayEvaluateEmulator, GatewayEvaluateFault, GatewayEvaluateFaultKind, GatewayEvaluateLedgerEntry, GatewayEvaluateScriptedTurn, GatewayFault, GatewayFaultKind, GatewayFaultMatch, GatewayFaultState, GatewayLedgerEntry, GatewayRouteCoverage, GatewayScriptedCompletion, GatewayScriptedError, GatewayScriptedToolCall, GatewayScriptedTurn, GatewayScriptedUsage, emulatorEvidenceHeader, gatewayChatCompletionsPath, gatewayEmulatorDefaultEventsPerChunk, gatewayEmulatorDefaultModels, gatewayEmulatorDefaultReasoningModels, gatewayEmulatorRoutes, gatewayEvaluateEmulatorRoutes, gatewayEvaluatePath, makeGatewayEmulator };
272
+ //# sourceMappingURL=gateway.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gateway.d.mts","names":[],"sources":["../src/gateway.ts"],"mappings":";;;;;;cA0Ea,0BAAA;;cAGA,mBAAA;;cAGA,4BAAA,EAA8B,aAAa;AAHxD;AAAA,cAWa,qCAAA,EAAuC,aAAa;;;AAXjC;AAGhC;;cAkBa,oCAAA;;AAlB2C;AAQxD;;cAgBa,qBAAA,EAAuB,aAAa,CAAC,qBAAA;;AAhBe;AAUjE;;cA2Ba,6BAAA,EAA+B,aAAa,CAAC,qBAAA;;cAkB7C,iBAAA,EAAiB,MAAA,CAAA,MAAA;EAAA;;;KAElB,iBAAA,GAAoB,cAAc;AAzCyB;AAqBvE;;;;AAA+E;AAkB/E;;;;;;;;;;;;;;AAvCuE,cA+D1D,YAAA,EAAY,MAAA,CAAA,KAAA,WAAA,MAAA,CAAA,MAAA;EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;KAEb,YAAA,GAAe,SAAS;AAAA,KAExB,gBAAA,GAAmB,aAAa;;;;;;cAO/B,oBAAA,EAAoB,MAAA,CAAA,MAAA;EAAA;;;;KAErB,oBAAA,GAAuB,iBAAiB;;cAGvC,uBAAA,EAAuB,MAAA,CAAA,MAAA;EAAA;;;;KAExB,uBAAA,GAA0B,oBAAoB;;;;;;;;;cAU7C,yBAAA,EAAyB,MAAA,CAAA,MAAA;EAAA;;;;;;;;;;;;;;;;KAE1B,yBAAA,GAA4B,+BAA+B;;cAG1D,oBAAA,EAAoB,MAAA,CAAA,MAAA;EAAA;;;;;;KAErB,oBAAA,GAAuB,iBAAiB;;cAGvC,mBAAA,EAAmB,MAAA,CAAA,KAAA,WAAA,MAAA,CAAA,MAAA;EAAA;;;;;;;;;;;;;;;;;;;;;;KAEpB,mBAAA,GAAsB,yBAAyB;AAAA,cAAA,gCAAA;;;;;;;cAM9C,2BAAA,SAAoC,gCAAA;EAAA,SACtC,KAAA;EAAA,SACA,MAAA;AAAA;EAAA,IAEI,OAAA,CAAA;AAAA;AAAA,KAKH,kBAAA,GAAqB,eAAe;AAAA,KAEpC,iBAAA,GAAoB,cAAc;AAAA,KAElC,oBAAA,GAAuB,iBAAiB;AAAA,KAExC,eAAA,GAAkB,YAAY;AAAA,KAE9B,sBAAA;mFAED,WAAA,GAAc,aAAA;WAEd,eAAA,GAAkB,aAAa;;;;;;;;WAQ/B,cAAA;AAAA;;cAIE,oBAAA,EAAoB,MAAA,CAAA,KAAA,WAAA,MAAA,CAAA,MAAA;EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;KAErB,oBAAA,GAAuB,iBAAiB;AAAA,KAExC,wBAAA,GAA2B,qBAAqB;AAjF5D;AAAA,KAoFY,2BAAA,GAA8B,wBAAwB;AAAA,KAEtD,0BAAA,GAA6B,uBAAuB;AAAA,KAEpD,uBAAA,GAA0B,oBAAoB;AAxFtB;AAAA,KA2FxB,eAAA,GAAkB,uBAAA,CAAwB,mBAAA;EAAA,SAC3C,QAAA,EAAU,uBAAA;AAAA;;AA1FuB;AAO5C;;;;;;;;;;;;;;;;;;;;;;;;;AAEA;;;;AAAoD;AAGpD;;;;;;;cAiSa,mBAAA,GAAuB,OAAA,GAAS,sBAAA,KAA8B,eAyD1E"}