@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,532 @@
1
+ import { emulatorRouteKey } from "./route-evidence.mjs";
2
+ import { ChunkCount, EmulatorErrorAfterChunksFault, EmulatorScriptedError, EmulatorStatusFault, EmulatorTruncateAfterChunksFault, approximateTokens, controlError, emulatorFaultFields, isJsonObject, jsonField, jsonResponse, makeEmulatorKernel, parseJson, readText, splitFragments, stringField, synthesizeValue } from "./emulator-kernel.mjs";
3
+ import { Predicate, Result } from "effect";
4
+ import * as Schema from "effect/Schema";
5
+ //#region src/messages.ts
6
+ /**
7
+ * Anthropic Messages emulator core (internal; not a package export).
8
+ *
9
+ * One `POST /v1/messages` route with request parsing (`model`, `max_tokens`, `system`,
10
+ * `messages`, `tools`, `tool_choice`, `thinking`, `stream`), Messages SSE framing in the order
11
+ * the real API sends it (`message_start`, then per content block `content_block_start`, its
12
+ * deltas, and `content_block_stop`, a `ping` after the first block starts, then `message_delta`
13
+ * with the stop reason and usage, and `message_stop`), the non-streamed `message` JSON body,
14
+ * scripted turns, and the `{ type: 'error', error: { type, message } }` envelope. Faults, the
15
+ * request ledger, the `/_emulate/*` control plane, evidence tagging, and route binding come from
16
+ * the shared kernel (`emulator-kernel.ts`).
17
+ *
18
+ * Content blocks: `thinking` (`thinking_delta` fragments, then one `signature_delta`) when the
19
+ * request enables thinking, `text` (`text_delta`), and `tool_use` (`input_json_delta` fragments
20
+ * of the tool input). Stop reasons: `end_turn`, `tool_use`, and `max_tokens` (the default answer
21
+ * is cut when it would exceed the request's `max_tokens`; scripted turns name any reason).
22
+ *
23
+ * Requests authenticate with a non-empty `x-api-key` (native API) or `Authorization: Bearer`
24
+ * (OAuth) credential; neither value is ever checked or stored. They must send a supported
25
+ * `anthropic-version` (`2023-06-01`, the value the SDK providers send); a missing or other value
26
+ * answers 400 `invalid_request_error`. `thinking` together with a forced `tool_choice` (`tool` or
27
+ * `any`) answers 400 as well. Other API constraints (the OAuth `anthropic-beta` header for bearer
28
+ * credentials, `budget_tokens` limits) are not enforced.
29
+ *
30
+ * Runtime-portable Web APIs only (`Request`, `Response`, `ReadableStream`, `TextEncoder`, `URL`);
31
+ * no Node builtins and no SDK imports.
32
+ */
33
+ /** An Anthropic wire error: `type` (for example `overloaded_error`) and a message. */
34
+ const MessagesWireError = Schema.Struct({
35
+ type: Schema.NonEmptyString,
36
+ message: Schema.String
37
+ });
38
+ /**
39
+ * Send `chunks` SSE events, then one `event: error` event (default `overloaded_error`) and close
40
+ * without `message_stop`. Streamed responses only; it must come before `message_stop`.
41
+ */
42
+ const MessagesErrorEventFault = Schema.Struct({
43
+ kind: Schema.Literal("error-event-after-chunks"),
44
+ chunks: ChunkCount,
45
+ error: Schema.optionalKey(MessagesWireError),
46
+ ...emulatorFaultFields
47
+ });
48
+ /**
49
+ * Wire faults: `status` (the body defaults to an Anthropic error envelope matching the status,
50
+ * for example `rate_limit_error` for 429 and `overloaded_error` for 529), `error-after-chunks`
51
+ * (a dropped connection), `truncate-after-chunks` (a clean close, for example before
52
+ * `message_stop`), and `error-event-after-chunks` (a mid-stream `error` event).
53
+ */
54
+ const MessagesFault = Schema.Union([
55
+ EmulatorStatusFault,
56
+ EmulatorErrorAfterChunksFault,
57
+ EmulatorTruncateAfterChunksFault,
58
+ MessagesErrorEventFault
59
+ ]);
60
+ const TokenCount = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0));
61
+ /** Usage for a scripted turn (sent in `message_start` and `message_delta`). */
62
+ const MessagesScriptedUsage = Schema.Struct({
63
+ inputTokens: TokenCount,
64
+ outputTokens: TokenCount
65
+ });
66
+ /** One scripted `tool_use` block; its JSON input streams as these `input_json_delta` fragments. */
67
+ const MessagesScriptedToolUse = Schema.Struct({
68
+ name: Schema.NonEmptyString,
69
+ inputFragments: Schema.Array(Schema.String),
70
+ id: Schema.optionalKey(Schema.NonEmptyString)
71
+ });
72
+ /**
73
+ * A scripted message. Every field is exact (nothing is filled in) except: a block is sent only
74
+ * when its field is present; `usage` omitted is synthesized and `null` drops `usage` from the
75
+ * wire; `stopReason` omitted is `tool_use` with tool uses, else `end_turn`; `order` defaults to
76
+ * `thinking-first` (`text-first` sends the thinking block after the text).
77
+ */
78
+ const MessagesScriptedMessage = Schema.Struct({
79
+ thinking: Schema.optionalKey(Schema.Array(Schema.String)),
80
+ text: Schema.optionalKey(Schema.Array(Schema.String)),
81
+ toolUses: Schema.optionalKey(Schema.Array(MessagesScriptedToolUse)),
82
+ order: Schema.optionalKey(Schema.Literals(["thinking-first", "text-first"])),
83
+ usage: Schema.optionalKey(Schema.NullOr(MessagesScriptedUsage)),
84
+ stopReason: Schema.optionalKey(Schema.NonEmptyString)
85
+ });
86
+ /** A turn queued for the next Messages request. */
87
+ const MessagesScriptedTurn = Schema.Union([EmulatorScriptedError, MessagesScriptedMessage]);
88
+ const MessagesTool = Schema.Struct({
89
+ name: Schema.String,
90
+ type: Schema.optionalKey(Schema.String),
91
+ description: Schema.optionalKey(Schema.String),
92
+ input_schema: Schema.optionalKey(Schema.Json)
93
+ });
94
+ const MessagesRequest = Schema.Struct({
95
+ model: Schema.optionalKey(Schema.String),
96
+ max_tokens: Schema.optionalKey(Schema.Json),
97
+ system: Schema.optionalKey(Schema.Json),
98
+ messages: Schema.Array(Schema.Json),
99
+ tools: Schema.optionalKey(Schema.NullOr(Schema.Array(MessagesTool))),
100
+ tool_choice: Schema.optionalKey(Schema.Json),
101
+ thinking: Schema.optionalKey(Schema.Json),
102
+ stream: Schema.optionalKey(Schema.NullOr(Schema.Boolean))
103
+ });
104
+ const decodeMessagesRequest = Schema.decodeUnknownResult(MessagesRequest);
105
+ const bearerPattern = /^bearer\s+\S+/i;
106
+ /** `anthropic-version` values the emulator accepts; the SDK providers send `2023-06-01` by default. */
107
+ const supportedAnthropicVersions = ["2023-06-01"];
108
+ const defaultText = [
109
+ "Hello",
110
+ " from the",
111
+ " synthetic Anthropic emulator."
112
+ ];
113
+ const defaultThinking = ["The user wants a short greeting.", " Reply briefly."];
114
+ const syntheticSignature = "synthetic-thinking-signature";
115
+ const thinkingRequested = (request) => {
116
+ const type = stringField(request.thinking, "type");
117
+ return type === "enabled" || type === "adaptive";
118
+ };
119
+ const forcedToolUse = (request) => {
120
+ const choice = stringField(request.tool_choice, "type");
121
+ return choice === "tool" || choice === "any";
122
+ };
123
+ const chosenTool = (request) => {
124
+ const tools = request.tools ?? [];
125
+ const choice = stringField(request.tool_choice, "type");
126
+ if (tools.length === 0 || choice === "none") return;
127
+ const forced = choice === "tool" ? stringField(request.tool_choice, "name") : void 0;
128
+ return tools.find((tool) => tool.name === forced) ?? tools[0];
129
+ };
130
+ /**
131
+ * Cut the plan so its synthetic output fits `maxTokens` (about four characters per token):
132
+ * thinking and text are cut mid-fragment, a tool call that does not fit is dropped, and the stop
133
+ * reason becomes `max_tokens`.
134
+ */
135
+ const fitToMaxTokens = (plan, maxTokens) => {
136
+ let budget = maxTokens * 4;
137
+ const blocks = [];
138
+ for (const block of plan.blocks) {
139
+ const size = block.fragments.join("").length;
140
+ if (size <= budget) {
141
+ blocks.push(block);
142
+ budget -= size;
143
+ continue;
144
+ }
145
+ if (block.type !== "tool_use" && budget > 0) {
146
+ const fragments = [];
147
+ for (const fragment of block.fragments) {
148
+ if (budget <= 0) break;
149
+ fragments.push(fragment.slice(0, budget));
150
+ budget -= Math.min(fragment.length, budget);
151
+ }
152
+ blocks.push({
153
+ type: block.type,
154
+ fragments
155
+ });
156
+ }
157
+ return {
158
+ blocks,
159
+ usage: plan.usage,
160
+ stopReason: "max_tokens"
161
+ };
162
+ }
163
+ return plan;
164
+ };
165
+ const defaultPlan = (request, seq, maxTokens) => {
166
+ const thinking = thinkingRequested(request) ? [{
167
+ type: "thinking",
168
+ fragments: defaultThinking
169
+ }] : [];
170
+ const tool = chosenTool(request);
171
+ if (tool === void 0) return fitToMaxTokens({
172
+ blocks: [...thinking, {
173
+ type: "text",
174
+ fragments: defaultText
175
+ }],
176
+ usage: void 0,
177
+ stopReason: "end_turn"
178
+ }, maxTokens);
179
+ const input = JSON.stringify(synthesizeValue(tool.input_schema ?? { type: "object" }, tool.name, 0));
180
+ return fitToMaxTokens({
181
+ blocks: [...thinking, {
182
+ type: "tool_use",
183
+ id: `toolu_synthetic_${seq}_0`,
184
+ name: tool.name,
185
+ fragments: ["", ...splitFragments(input, 3)]
186
+ }],
187
+ usage: void 0,
188
+ stopReason: "tool_use"
189
+ }, maxTokens);
190
+ };
191
+ const scriptedPlan = (turn, seq) => {
192
+ const thinking = turn.thinking === void 0 ? [] : [{
193
+ type: "thinking",
194
+ fragments: turn.thinking
195
+ }];
196
+ const text = turn.text === void 0 ? [] : [{
197
+ type: "text",
198
+ fragments: turn.text
199
+ }];
200
+ const toolUses = (turn.toolUses ?? []).map((call, index) => ({
201
+ type: "tool_use",
202
+ id: call.id ?? `toolu_synthetic_${seq}_${index}`,
203
+ name: call.name,
204
+ fragments: call.inputFragments
205
+ }));
206
+ return {
207
+ blocks: turn.order === "text-first" ? [
208
+ ...text,
209
+ ...thinking,
210
+ ...toolUses
211
+ ] : [
212
+ ...thinking,
213
+ ...text,
214
+ ...toolUses
215
+ ],
216
+ usage: turn.usage,
217
+ stopReason: turn.stopReason ?? (toolUses.length > 0 ? "tool_use" : "end_turn")
218
+ };
219
+ };
220
+ const planUsage = (plan, requestText) => {
221
+ if (plan.usage === null) return;
222
+ return plan.usage ?? {
223
+ inputTokens: approximateTokens(requestText),
224
+ outputTokens: approximateTokens(plan.blocks.flatMap((block) => block.fragments).join(""))
225
+ };
226
+ };
227
+ const wireUsage = (inputTokens, outputTokens) => ({
228
+ input_tokens: inputTokens,
229
+ cache_creation_input_tokens: 0,
230
+ cache_read_input_tokens: 0,
231
+ output_tokens: outputTokens
232
+ });
233
+ const sseEvent = (type, payload) => `event: ${type}\ndata: ${JSON.stringify({
234
+ type,
235
+ ...payload
236
+ })}\n\n`;
237
+ const blockStart = (block) => {
238
+ switch (block.type) {
239
+ case "thinking": return {
240
+ type: "thinking",
241
+ thinking: "",
242
+ signature: ""
243
+ };
244
+ case "text": return {
245
+ type: "text",
246
+ text: ""
247
+ };
248
+ case "tool_use": return {
249
+ type: "tool_use",
250
+ id: block.id,
251
+ name: block.name,
252
+ input: {}
253
+ };
254
+ }
255
+ };
256
+ const blockDelta = (block, fragment) => {
257
+ switch (block.type) {
258
+ case "thinking": return {
259
+ type: "thinking_delta",
260
+ thinking: fragment
261
+ };
262
+ case "text": return {
263
+ type: "text_delta",
264
+ text: fragment
265
+ };
266
+ case "tool_use": return {
267
+ type: "input_json_delta",
268
+ partial_json: fragment
269
+ };
270
+ }
271
+ };
272
+ /** SSE events for a streamed message, one network chunk each, in the real API's order. */
273
+ const streamEvents = (plan, identity, usage) => {
274
+ const message = {
275
+ id: identity.id,
276
+ type: "message",
277
+ role: "assistant",
278
+ model: identity.model,
279
+ content: [],
280
+ stop_reason: null,
281
+ stop_sequence: null
282
+ };
283
+ if (usage !== void 0) message.usage = wireUsage(usage.inputTokens, 1);
284
+ const events = [sseEvent("message_start", { message })];
285
+ const ping = sseEvent("ping", {});
286
+ plan.blocks.forEach((block, index) => {
287
+ events.push(sseEvent("content_block_start", {
288
+ index,
289
+ content_block: blockStart(block)
290
+ }));
291
+ if (index === 0) events.push(ping);
292
+ for (const fragment of block.fragments) events.push(sseEvent("content_block_delta", {
293
+ index,
294
+ delta: blockDelta(block, fragment)
295
+ }));
296
+ if (block.type === "thinking") events.push(sseEvent("content_block_delta", {
297
+ index,
298
+ delta: {
299
+ type: "signature_delta",
300
+ signature: syntheticSignature
301
+ }
302
+ }));
303
+ events.push(sseEvent("content_block_stop", { index }));
304
+ });
305
+ if (plan.blocks.length === 0) events.push(ping);
306
+ const messageDelta = { delta: {
307
+ stop_reason: plan.stopReason,
308
+ stop_sequence: null
309
+ } };
310
+ if (usage !== void 0) messageDelta.usage = wireUsage(usage.inputTokens, usage.outputTokens);
311
+ events.push(sseEvent("message_delta", messageDelta));
312
+ events.push(sseEvent("message_stop", {}));
313
+ return events;
314
+ };
315
+ /** The JSON value of a tool input; throws (answering an emulator 500) when it is not JSON. */
316
+ const toolInput = (fragments) => {
317
+ const text = fragments.join("");
318
+ const parsed = text.trim().length === 0 ? {} : parseJson(text);
319
+ if (parsed === void 0) throw new Error("scripted tool input is not JSON");
320
+ return parsed;
321
+ };
322
+ /** The non-streamed `message` JSON body. */
323
+ const messageBody = (plan, identity, usage) => {
324
+ const content = plan.blocks.map((block) => {
325
+ switch (block.type) {
326
+ case "thinking": return {
327
+ type: "thinking",
328
+ thinking: block.fragments.join(""),
329
+ signature: syntheticSignature
330
+ };
331
+ case "text": return {
332
+ type: "text",
333
+ text: block.fragments.join("")
334
+ };
335
+ case "tool_use": return {
336
+ type: "tool_use",
337
+ id: block.id,
338
+ name: block.name,
339
+ input: toolInput(block.fragments)
340
+ };
341
+ }
342
+ });
343
+ const body = {
344
+ id: identity.id,
345
+ type: "message",
346
+ role: "assistant",
347
+ model: identity.model,
348
+ content,
349
+ stop_reason: plan.stopReason,
350
+ stop_sequence: null
351
+ };
352
+ if (usage !== void 0) body.usage = wireUsage(usage.inputTokens, usage.outputTokens);
353
+ return body;
354
+ };
355
+ /** The Anthropic error envelope. */
356
+ const messagesErrorEnvelope = (error) => ({
357
+ type: "error",
358
+ error: {
359
+ type: error.type,
360
+ message: error.message
361
+ }
362
+ });
363
+ const errorTypeForStatus = (status) => {
364
+ switch (status) {
365
+ case 400: return "invalid_request_error";
366
+ case 401: return "authentication_error";
367
+ case 402: return "billing_error";
368
+ case 403: return "permission_error";
369
+ case 404: return "not_found_error";
370
+ case 413: return "request_too_large";
371
+ case 429: return "rate_limit_error";
372
+ case 529: return "overloaded_error";
373
+ default: return "api_error";
374
+ }
375
+ };
376
+ const defaultFaultMessage = (status) => {
377
+ switch (status) {
378
+ case 429: return "Synthetic rate limit: too many requests.";
379
+ case 529: return "Synthetic: overloaded.";
380
+ default: return `Synthetic upstream error (${status}).`;
381
+ }
382
+ };
383
+ const defaultFaultBody = (status) => messagesErrorEnvelope({
384
+ type: errorTypeForStatus(status),
385
+ message: defaultFaultMessage(status)
386
+ });
387
+ const defaultErrorEvent = {
388
+ type: "overloaded_error",
389
+ message: "Synthetic: overloaded."
390
+ };
391
+ const credentialHeaderOf = (request) => {
392
+ if ((request.headers.get("x-api-key") ?? "").trim().length > 0) return "x-api-key";
393
+ return bearerPattern.test(request.headers.get("authorization") ?? "") ? "authorization" : void 0;
394
+ };
395
+ const isPositiveInteger = (value) => Predicate.isNumber(value) && Number.isSafeInteger(value) && value > 0;
396
+ /**
397
+ * Create a Messages emulator from its config. Each call has independent ledger, fault, and
398
+ * script state.
399
+ *
400
+ * Precedence per request: authentication, a supported `anthropic-version`, JSON and request
401
+ * validation (including a positive integer `max_tokens`, and no `thinking` with a forced
402
+ * `tool_choice`), then the first matching fault if it is a `status` fault, then the next
403
+ * scripted turn, then model validation and defaults; a first matching body fault then shapes the
404
+ * body. Only the first matching fault (in insertion order) applies. Credential headers are never
405
+ * recorded, and credential values are never checked or stored.
406
+ */
407
+ const makeMessagesEmulator = (config) => {
408
+ const knownModels = [...config.knownModels];
409
+ const errorResponse = (status, error) => jsonResponse(status, messagesErrorEnvelope(error));
410
+ const invalidRequest = (message) => errorResponse(400, {
411
+ type: "invalid_request_error",
412
+ message
413
+ });
414
+ const kernel = makeEmulatorKernel({
415
+ routes: config.routes,
416
+ faultSchema: MessagesFault,
417
+ turnSchema: MessagesScriptedTurn,
418
+ newEntry: (base) => ({
419
+ ...base,
420
+ toolNames: []
421
+ }),
422
+ snapshotEntry: (entry) => ({
423
+ ...entry,
424
+ toolNames: [...entry.toolNames]
425
+ }),
426
+ unknownRoute: () => errorResponse(404, {
427
+ type: "not_found_error",
428
+ message: "Synthetic: no emulated route."
429
+ }),
430
+ stateFields: () => ({ knownModels }),
431
+ inputInvalid: config.inputInvalid
432
+ });
433
+ const messages = async (request, entry, path) => {
434
+ const credentialHeader = credentialHeaderOf(request);
435
+ if (credentialHeader === void 0) {
436
+ entry.status = 401;
437
+ return errorResponse(401, {
438
+ type: "authentication_error",
439
+ message: "Synthetic: an x-api-key header or a bearer credential is required."
440
+ });
441
+ }
442
+ entry.credentialHeader = credentialHeader;
443
+ const version = request.headers.get("anthropic-version");
444
+ const beta = request.headers.get("anthropic-beta");
445
+ if (version !== null) entry.anthropicVersion = version;
446
+ if (beta !== null) entry.anthropicBeta = beta;
447
+ if (version === null || !supportedAnthropicVersions.includes(version)) {
448
+ entry.status = 400;
449
+ return invalidRequest(version === null ? "Synthetic: the anthropic-version header is required." : "Synthetic: the anthropic-version header value is not supported.");
450
+ }
451
+ const text = await readText(request);
452
+ const json = text === void 0 ? void 0 : parseJson(text);
453
+ if (text === void 0 || json === void 0) {
454
+ entry.status = 400;
455
+ return invalidRequest("Synthetic: the request body is not valid JSON.");
456
+ }
457
+ entry.body = json;
458
+ const decoded = decodeMessagesRequest(json);
459
+ if (Result.isFailure(decoded) || !isJsonObject(json)) {
460
+ entry.status = 400;
461
+ return invalidRequest("Synthetic: the request body is not a Messages request.");
462
+ }
463
+ const body = decoded.success;
464
+ const seq = entry.seq;
465
+ if (body.model !== void 0) entry.model = body.model;
466
+ entry.stream = body.stream === true;
467
+ entry.toolNames = (body.tools ?? []).map((tool) => tool.name);
468
+ if (Predicate.isNumber(body.max_tokens)) entry.maxTokens = body.max_tokens;
469
+ if (body.thinking !== void 0) entry.thinking = body.thinking;
470
+ if (body.tool_choice !== void 0) entry.toolChoice = body.tool_choice;
471
+ const maxTokens = jsonField(json, "max_tokens");
472
+ if (!isPositiveInteger(maxTokens)) {
473
+ entry.status = 400;
474
+ return invalidRequest("Synthetic: max_tokens must be a positive integer.");
475
+ }
476
+ if (thinkingRequested(body) && forcedToolUse(body)) {
477
+ entry.status = 400;
478
+ return invalidRequest("Synthetic: thinking may not be enabled when tool_choice forces tool use.");
479
+ }
480
+ const fault = kernel.takeFault(path, body.model);
481
+ if (fault !== void 0 && fault.fault.kind === "status") return kernel.respondWithStatusFault(entry, fault, fault.fault, defaultFaultBody);
482
+ const errorEventFault = fault !== void 0 && fault.fault.kind === "error-event-after-chunks" ? {
483
+ state: fault,
484
+ fault: fault.fault
485
+ } : void 0;
486
+ const cannotApply = (problem) => {
487
+ entry.faultError = problem;
488
+ entry.status = 500;
489
+ return controlError(500, `emulator fault cannot apply: ${problem}`);
490
+ };
491
+ const turn = kernel.nextTurn();
492
+ if (turn !== void 0 && "error" in turn) {
493
+ entry.scripted = "error";
494
+ if (errorEventFault !== void 0) return cannotApply("error-event-after-chunks cannot apply to a scripted error");
495
+ return kernel.respondWithScriptedError(entry, turn.error, fault);
496
+ }
497
+ if (turn === void 0 && (body.model === void 0 || !knownModels.includes(body.model))) {
498
+ entry.status = 404;
499
+ return errorResponse(404, {
500
+ type: "not_found_error",
501
+ message: "Synthetic placeholder: the requested model was not found."
502
+ });
503
+ }
504
+ if (turn !== void 0) entry.scripted = "message";
505
+ const plan = turn === void 0 ? defaultPlan(body, seq, maxTokens) : scriptedPlan(turn, seq);
506
+ const identity = {
507
+ id: `msg_synthetic_${seq}`,
508
+ model: body.model ?? "unknown"
509
+ };
510
+ const usage = planUsage(plan, text);
511
+ if (body.stream !== true) {
512
+ if (errorEventFault !== void 0) return cannotApply("error-event-after-chunks cannot apply to a non-streamed response");
513
+ return kernel.respondWithBody(entry, 200, { "content-type": "application/json" }, [JSON.stringify(messageBody(plan, identity, usage))], fault);
514
+ }
515
+ const events = streamEvents(plan, identity, usage);
516
+ const headers = {
517
+ "content-type": "text/event-stream",
518
+ "cache-control": "no-cache"
519
+ };
520
+ if (errorEventFault === void 0) return kernel.respondWithBody(entry, 200, headers, events, fault);
521
+ const after = errorEventFault.fault.chunks;
522
+ if (after >= events.length) return cannotApply(`error-event-after-chunks after ${after} chunk(s) cannot apply to a response with ${events.length} chunk(s)`);
523
+ const response = kernel.respondWithBody(entry, 200, headers, [...events.slice(0, after), sseEvent("error", { error: { ...errorEventFault.fault.error ?? defaultErrorEvent } })], void 0);
524
+ kernel.consumeFault(errorEventFault.state, entry);
525
+ return response;
526
+ };
527
+ return kernel.serve(new Map([[emulatorRouteKey("POST", config.path), messages]]));
528
+ };
529
+ //#endregion
530
+ export { MessagesErrorEventFault, MessagesFault, MessagesScriptedMessage, MessagesScriptedToolUse, MessagesScriptedTurn, MessagesScriptedUsage, MessagesWireError, makeMessagesEmulator, messagesErrorEnvelope };
531
+
532
+ //# sourceMappingURL=messages.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.mjs","names":[],"sources":["../src/messages.ts"],"sourcesContent":["/**\n * Anthropic Messages emulator core (internal; not a package export).\n *\n * One `POST /v1/messages` route with request parsing (`model`, `max_tokens`, `system`,\n * `messages`, `tools`, `tool_choice`, `thinking`, `stream`), Messages SSE framing in the order\n * the real API sends it (`message_start`, then per content block `content_block_start`, its\n * deltas, and `content_block_stop`, a `ping` after the first block starts, then `message_delta`\n * with the stop reason and usage, and `message_stop`), the non-streamed `message` JSON body,\n * scripted turns, and the `{ type: 'error', error: { type, message } }` envelope. Faults, the\n * request ledger, the `/_emulate/*` control plane, evidence tagging, and route binding come from\n * the shared kernel (`emulator-kernel.ts`).\n *\n * Content blocks: `thinking` (`thinking_delta` fragments, then one `signature_delta`) when the\n * request enables thinking, `text` (`text_delta`), and `tool_use` (`input_json_delta` fragments\n * of the tool input). Stop reasons: `end_turn`, `tool_use`, and `max_tokens` (the default answer\n * is cut when it would exceed the request's `max_tokens`; scripted turns name any reason).\n *\n * Requests authenticate with a non-empty `x-api-key` (native API) or `Authorization: Bearer`\n * (OAuth) credential; neither value is ever checked or stored. They must send a supported\n * `anthropic-version` (`2023-06-01`, the value the SDK providers send); a missing or other value\n * answers 400 `invalid_request_error`. `thinking` together with a forced `tool_choice` (`tool` or\n * `any`) answers 400 as well. Other API constraints (the OAuth `anthropic-beta` header for bearer\n * credentials, `budget_tokens` limits) are not enforced.\n *\n * Runtime-portable Web APIs only (`Request`, `Response`, `ReadableStream`, `TextEncoder`, `URL`);\n * no Node builtins and no SDK imports.\n */\nimport { Predicate, Result } from 'effect'\nimport * as Schema from 'effect/Schema'\nimport {\n approximateTokens,\n ChunkCount,\n controlError,\n EmulatorErrorAfterChunksFault,\n emulatorFaultFields,\n EmulatorScriptedError,\n EmulatorStatusFault,\n EmulatorTruncateAfterChunksFault,\n isJsonObject,\n jsonField,\n jsonResponse,\n makeEmulatorKernel,\n parseJson,\n readText,\n splitFragments,\n stringField,\n synthesizeValue,\n type EmulatorApi,\n type KernelLedgerEntry\n} from './emulator-kernel.ts'\nimport {\n emulatorRouteKey,\n type EmulatorEvidence,\n type EmulatorRouteEvidence\n} from './route-evidence.ts'\n\n/** An Anthropic wire error: `type` (for example `overloaded_error`) and a message. */\nexport const MessagesWireError = Schema.Struct({\n type: Schema.NonEmptyString,\n message: Schema.String\n})\n\nexport type MessagesWireError = typeof MessagesWireError.Type\n\n/**\n * Send `chunks` SSE events, then one `event: error` event (default `overloaded_error`) and close\n * without `message_stop`. Streamed responses only; it must come before `message_stop`.\n */\nexport const MessagesErrorEventFault = Schema.Struct({\n kind: Schema.Literal('error-event-after-chunks'),\n chunks: ChunkCount,\n error: Schema.optionalKey(MessagesWireError),\n ...emulatorFaultFields\n})\n\n/**\n * Wire faults: `status` (the body defaults to an Anthropic error envelope matching the status,\n * for example `rate_limit_error` for 429 and `overloaded_error` for 529), `error-after-chunks`\n * (a dropped connection), `truncate-after-chunks` (a clean close, for example before\n * `message_stop`), and `error-event-after-chunks` (a mid-stream `error` event).\n */\nexport const MessagesFault = Schema.Union([\n EmulatorStatusFault,\n EmulatorErrorAfterChunksFault,\n EmulatorTruncateAfterChunksFault,\n MessagesErrorEventFault\n])\n\nexport type MessagesFault = typeof MessagesFault.Type\n\nexport type MessagesFaultKind = MessagesFault['kind']\n\nconst TokenCount = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0))\n\n/** Usage for a scripted turn (sent in `message_start` and `message_delta`). */\nexport const MessagesScriptedUsage = Schema.Struct({\n inputTokens: TokenCount,\n outputTokens: TokenCount\n})\n\nexport type MessagesScriptedUsage = typeof MessagesScriptedUsage.Type\n\n/** One scripted `tool_use` block; its JSON input streams as these `input_json_delta` fragments. */\nexport const MessagesScriptedToolUse = Schema.Struct({\n name: Schema.NonEmptyString,\n inputFragments: Schema.Array(Schema.String),\n id: Schema.optionalKey(Schema.NonEmptyString)\n})\n\nexport type MessagesScriptedToolUse = typeof MessagesScriptedToolUse.Type\n\n/**\n * A scripted message. Every field is exact (nothing is filled in) except: a block is sent only\n * when its field is present; `usage` omitted is synthesized and `null` drops `usage` from the\n * wire; `stopReason` omitted is `tool_use` with tool uses, else `end_turn`; `order` defaults to\n * `thinking-first` (`text-first` sends the thinking block after the text).\n */\nexport const MessagesScriptedMessage = Schema.Struct({\n thinking: Schema.optionalKey(Schema.Array(Schema.String)),\n text: Schema.optionalKey(Schema.Array(Schema.String)),\n toolUses: Schema.optionalKey(Schema.Array(MessagesScriptedToolUse)),\n order: Schema.optionalKey(Schema.Literals(['thinking-first', 'text-first'])),\n usage: Schema.optionalKey(Schema.NullOr(MessagesScriptedUsage)),\n stopReason: Schema.optionalKey(Schema.NonEmptyString)\n})\n\nexport type MessagesScriptedMessage = typeof MessagesScriptedMessage.Type\n\n/** A turn queued for the next Messages request. */\nexport const MessagesScriptedTurn = Schema.Union([EmulatorScriptedError, MessagesScriptedMessage])\n\nexport type MessagesScriptedTurn = typeof MessagesScriptedTurn.Type\n\nexport type MessagesLedgerEntry = {\n /** 1-based arrival order since the last ledger clear or reset. */\n readonly seq: number\n readonly method: string\n readonly path: string\n /** Parsed JSON request body, when it was valid JSON. */\n readonly body?: Schema.Json\n readonly model?: string\n readonly stream?: boolean\n /** The request's `max_tokens`, when it is a number (non-positive or fractional answers 400). */\n readonly maxTokens?: number\n readonly thinking?: Schema.Json\n readonly toolChoice?: Schema.Json\n readonly toolNames: ReadonlyArray<string>\n /** Which header carried the credential (the value is never recorded). */\n readonly credentialHeader?: 'x-api-key' | 'authorization'\n readonly anthropicVersion?: string\n readonly anthropicBeta?: string\n /** Kind of the fault that shaped the response. */\n readonly fault?: MessagesFaultKind\n /** Why a matching fault could not take effect (the response was a 500 emulator error). */\n readonly faultError?: string\n /**\n * Set when the emulator could not build the planned response; the request was answered with a\n * 500 emulator error (still evidence-tagged) and no fault was used up.\n */\n readonly responseError?: string\n /** Set when a scripted turn answered the request. */\n readonly scripted?: 'message' | 'error'\n /** Evidence of the matched route; `unknown-route` for requests that failed closed. */\n readonly evidence: EmulatorEvidence | 'unknown-route'\n readonly status: number\n /** Body chunks handed to the transport so far (each produced when pulled). */\n readonly bodyChunks: number\n}\n\nexport type MessagesEmulator = EmulatorApi<MessagesScriptedTurn, MessagesFault, MessagesLedgerEntry>\n\nexport type MessagesEmulatorConfig = {\n /** The Messages path, for example `/v1/messages`. */\n readonly path: string\n /** Route evidence manifest; must list exactly the Messages route. */\n readonly routes: ReadonlyArray<EmulatorRouteEvidence>\n readonly knownModels: ReadonlyArray<string>\n /** Builds the error thrown by the JS API (`faults.add`, `script.enqueue`) for invalid input. */\n readonly inputInvalid: (input: 'fault' | 'turn', reason: string) => Error\n}\n\nconst MessagesTool = Schema.Struct({\n name: Schema.String,\n type: Schema.optionalKey(Schema.String),\n description: Schema.optionalKey(Schema.String),\n input_schema: Schema.optionalKey(Schema.Json)\n})\n\nconst MessagesRequest = Schema.Struct({\n model: Schema.optionalKey(Schema.String),\n max_tokens: Schema.optionalKey(Schema.Json),\n system: Schema.optionalKey(Schema.Json),\n messages: Schema.Array(Schema.Json),\n tools: Schema.optionalKey(Schema.NullOr(Schema.Array(MessagesTool))),\n tool_choice: Schema.optionalKey(Schema.Json),\n thinking: Schema.optionalKey(Schema.Json),\n stream: Schema.optionalKey(Schema.NullOr(Schema.Boolean))\n})\n\ntype MessagesRequest = typeof MessagesRequest.Type\n\nconst decodeMessagesRequest = Schema.decodeUnknownResult(MessagesRequest)\n\n// A non-empty bearer credential. The value is never checked or stored.\nconst bearerPattern = /^bearer\\s+\\S+/i\n\n/** `anthropic-version` values the emulator accepts; the SDK providers send `2023-06-01` by default. */\nconst supportedAnthropicVersions: ReadonlyArray<string> = ['2023-06-01']\n\nconst defaultText = ['Hello', ' from the', ' synthetic Anthropic emulator.']\n\nconst defaultThinking = ['The user wants a short greeting.', ' Reply briefly.']\n\n// Opaque placeholder for the thinking-block signature the real API sends.\nconst syntheticSignature = 'synthetic-thinking-signature'\n\ntype BlockPlan =\n | { readonly type: 'thinking'; readonly fragments: ReadonlyArray<string> }\n | { readonly type: 'text'; readonly fragments: ReadonlyArray<string> }\n | {\n readonly type: 'tool_use'\n readonly id: string\n readonly name: string\n readonly fragments: ReadonlyArray<string>\n }\n\ntype MessagePlan = {\n readonly blocks: ReadonlyArray<BlockPlan>\n /** `null`: never send usage; `undefined`: synthesize. */\n readonly usage: MessagesScriptedUsage | null | undefined\n readonly stopReason: string\n}\n\nconst thinkingRequested = (request: MessagesRequest): boolean => {\n const type = stringField(request.thinking, 'type')\n\n return type === 'enabled' || type === 'adaptive'\n}\n\n// The real API rejects extended thinking when `tool_choice` forces tool use.\nconst forcedToolUse = (request: MessagesRequest): boolean => {\n const choice = stringField(request.tool_choice, 'type')\n\n return choice === 'tool' || choice === 'any'\n}\n\nconst chosenTool = (request: MessagesRequest) => {\n const tools = request.tools ?? []\n const choice = stringField(request.tool_choice, 'type')\n\n if (tools.length === 0 || choice === 'none') {\n return undefined\n }\n\n const forced = choice === 'tool' ? stringField(request.tool_choice, 'name') : undefined\n\n return tools.find(tool => tool.name === forced) ?? tools[0]\n}\n\n/**\n * Cut the plan so its synthetic output fits `maxTokens` (about four characters per token):\n * thinking and text are cut mid-fragment, a tool call that does not fit is dropped, and the stop\n * reason becomes `max_tokens`.\n */\nconst fitToMaxTokens = (plan: MessagePlan, maxTokens: number): MessagePlan => {\n let budget = maxTokens * 4\n const blocks: Array<BlockPlan> = []\n\n for (const block of plan.blocks) {\n const size = block.fragments.join('').length\n\n if (size <= budget) {\n blocks.push(block)\n budget -= size\n\n continue\n }\n\n if (block.type !== 'tool_use' && budget > 0) {\n const fragments: Array<string> = []\n\n for (const fragment of block.fragments) {\n if (budget <= 0) break\n\n fragments.push(fragment.slice(0, budget))\n budget -= Math.min(fragment.length, budget)\n }\n\n blocks.push({ type: block.type, fragments })\n }\n\n return { blocks, usage: plan.usage, stopReason: 'max_tokens' }\n }\n\n return plan\n}\n\nconst defaultPlan = (request: MessagesRequest, seq: number, maxTokens: number): MessagePlan => {\n const thinking: ReadonlyArray<BlockPlan> = thinkingRequested(request)\n ? [{ type: 'thinking', fragments: defaultThinking }]\n : []\n\n const tool = chosenTool(request)\n\n if (tool === undefined) {\n return fitToMaxTokens(\n {\n blocks: [...thinking, { type: 'text', fragments: defaultText }],\n usage: undefined,\n stopReason: 'end_turn'\n },\n maxTokens\n )\n }\n\n const input = JSON.stringify(\n synthesizeValue(tool.input_schema ?? { type: 'object' }, tool.name, 0)\n )\n\n return fitToMaxTokens(\n {\n blocks: [\n ...thinking,\n {\n type: 'tool_use',\n id: `toolu_synthetic_${seq}_0`,\n name: tool.name,\n // Emulator choice (unverified): open the input with an empty `partial_json` fragment.\n fragments: ['', ...splitFragments(input, 3)]\n }\n ],\n usage: undefined,\n stopReason: 'tool_use'\n },\n maxTokens\n )\n}\n\nconst scriptedPlan = (turn: MessagesScriptedMessage, seq: number): MessagePlan => {\n const thinking: ReadonlyArray<BlockPlan> =\n turn.thinking === undefined ? [] : [{ type: 'thinking', fragments: turn.thinking }]\n\n const text: ReadonlyArray<BlockPlan> =\n turn.text === undefined ? [] : [{ type: 'text', fragments: turn.text }]\n\n const toolUses = (turn.toolUses ?? []).map((call, index): BlockPlan => ({\n type: 'tool_use',\n id: call.id ?? `toolu_synthetic_${seq}_${index}`,\n name: call.name,\n fragments: call.inputFragments\n }))\n\n return {\n blocks:\n turn.order === 'text-first'\n ? [...text, ...thinking, ...toolUses]\n : [...thinking, ...text, ...toolUses],\n usage: turn.usage,\n stopReason: turn.stopReason ?? (toolUses.length > 0 ? 'tool_use' : 'end_turn')\n }\n}\n\ntype PlanUsage = { readonly inputTokens: number; readonly outputTokens: number } | undefined\n\nconst planUsage = (plan: MessagePlan, requestText: string): PlanUsage => {\n if (plan.usage === null) {\n return undefined\n }\n\n return (\n plan.usage ?? {\n inputTokens: approximateTokens(requestText),\n outputTokens: approximateTokens(plan.blocks.flatMap(block => block.fragments).join(''))\n }\n )\n}\n\ntype ResponseIdentity = { readonly id: string; readonly model: string }\n\n// Wire shapes of the Messages responses the emulator sends.\ntype WireUsage = {\n readonly input_tokens: number\n readonly cache_creation_input_tokens: number\n readonly cache_read_input_tokens: number\n readonly output_tokens: number\n}\n\ntype WireMessage = {\n readonly id: string\n readonly type: 'message'\n readonly role: 'assistant'\n readonly model: string\n readonly content: ReadonlyArray<Schema.JsonObject>\n readonly stop_reason: string | null\n readonly stop_sequence: null\n usage?: WireUsage\n}\n\ntype WireMessageDelta = {\n readonly delta: { readonly stop_reason: string; readonly stop_sequence: null }\n usage?: WireUsage\n}\n\nconst wireUsage = (inputTokens: number, outputTokens: number): WireUsage => ({\n input_tokens: inputTokens,\n cache_creation_input_tokens: 0,\n cache_read_input_tokens: 0,\n output_tokens: outputTokens\n})\n\nconst sseEvent = (type: string, payload: Schema.JsonObject): string =>\n `event: ${type}\\ndata: ${JSON.stringify({ type, ...payload })}\\n\\n`\n\nconst blockStart = (block: BlockPlan): Schema.JsonObject => {\n switch (block.type) {\n case 'thinking':\n return { type: 'thinking', thinking: '', signature: '' }\n case 'text':\n return { type: 'text', text: '' }\n case 'tool_use':\n return { type: 'tool_use', id: block.id, name: block.name, input: {} }\n }\n}\n\nconst blockDelta = (block: BlockPlan, fragment: string): Schema.JsonObject => {\n switch (block.type) {\n case 'thinking':\n return { type: 'thinking_delta', thinking: fragment }\n case 'text':\n return { type: 'text_delta', text: fragment }\n case 'tool_use':\n return { type: 'input_json_delta', partial_json: fragment }\n }\n}\n\n/** SSE events for a streamed message, one network chunk each, in the real API's order. */\nconst streamEvents = (\n plan: MessagePlan,\n identity: ResponseIdentity,\n usage: PlanUsage\n): ReadonlyArray<string> => {\n const message: WireMessage = {\n id: identity.id,\n type: 'message',\n role: 'assistant',\n model: identity.model,\n content: [],\n stop_reason: null,\n stop_sequence: null\n }\n\n if (usage !== undefined) {\n message.usage = wireUsage(usage.inputTokens, 1)\n }\n\n const events: Array<string> = [sseEvent('message_start', { message })]\n const ping = sseEvent('ping', {})\n\n plan.blocks.forEach((block, index) => {\n events.push(sseEvent('content_block_start', { index, content_block: blockStart(block) }))\n\n if (index === 0) {\n events.push(ping)\n }\n\n for (const fragment of block.fragments) {\n events.push(sseEvent('content_block_delta', { index, delta: blockDelta(block, fragment) }))\n }\n\n if (block.type === 'thinking') {\n events.push(\n sseEvent('content_block_delta', {\n index,\n delta: { type: 'signature_delta', signature: syntheticSignature }\n })\n )\n }\n\n events.push(sseEvent('content_block_stop', { index }))\n })\n\n if (plan.blocks.length === 0) {\n events.push(ping)\n }\n\n const messageDelta: WireMessageDelta = {\n delta: { stop_reason: plan.stopReason, stop_sequence: null }\n }\n\n // Same usage shape as the committed fixtures: input and cache counts alongside the cumulative\n // `output_tokens`. Unverified until a live recording confirms it.\n if (usage !== undefined) {\n messageDelta.usage = wireUsage(usage.inputTokens, usage.outputTokens)\n }\n\n events.push(sseEvent('message_delta', messageDelta))\n events.push(sseEvent('message_stop', {}))\n\n return events\n}\n\n/** The JSON value of a tool input; throws (answering an emulator 500) when it is not JSON. */\nconst toolInput = (fragments: ReadonlyArray<string>): Schema.Json => {\n const text = fragments.join('')\n const parsed = text.trim().length === 0 ? {} : parseJson(text)\n\n if (parsed === undefined) {\n throw new Error('scripted tool input is not JSON')\n }\n\n return parsed\n}\n\n/** The non-streamed `message` JSON body. */\nconst messageBody = (\n plan: MessagePlan,\n identity: ResponseIdentity,\n usage: PlanUsage\n): WireMessage => {\n const content = plan.blocks.map((block): Schema.JsonObject => {\n switch (block.type) {\n case 'thinking':\n return {\n type: 'thinking',\n thinking: block.fragments.join(''),\n signature: syntheticSignature\n }\n case 'text':\n return { type: 'text', text: block.fragments.join('') }\n case 'tool_use':\n return {\n type: 'tool_use',\n id: block.id,\n name: block.name,\n input: toolInput(block.fragments)\n }\n }\n })\n\n const body: WireMessage = {\n id: identity.id,\n type: 'message',\n role: 'assistant',\n model: identity.model,\n content,\n stop_reason: plan.stopReason,\n stop_sequence: null\n }\n\n if (usage !== undefined) {\n body.usage = wireUsage(usage.inputTokens, usage.outputTokens)\n }\n\n return body\n}\n\n/** The Anthropic error envelope. */\nexport const messagesErrorEnvelope = (error: MessagesWireError): Schema.JsonObject => ({\n type: 'error',\n error: { type: error.type, message: error.message }\n})\n\nconst errorTypeForStatus = (status: number): string => {\n switch (status) {\n case 400:\n return 'invalid_request_error'\n case 401:\n return 'authentication_error'\n case 402:\n return 'billing_error'\n case 403:\n return 'permission_error'\n case 404:\n return 'not_found_error'\n case 413:\n return 'request_too_large'\n case 429:\n return 'rate_limit_error'\n case 529:\n return 'overloaded_error'\n default:\n return 'api_error'\n }\n}\n\nconst defaultFaultMessage = (status: number): string => {\n switch (status) {\n case 429:\n return 'Synthetic rate limit: too many requests.'\n case 529:\n return 'Synthetic: overloaded.'\n default:\n return `Synthetic upstream error (${status}).`\n }\n}\n\nconst defaultFaultBody = (status: number): Schema.Json =>\n messagesErrorEnvelope({ type: errorTypeForStatus(status), message: defaultFaultMessage(status) })\n\nconst defaultErrorEvent: MessagesWireError = {\n type: 'overloaded_error',\n message: 'Synthetic: overloaded.'\n}\n\ntype MutableLedgerEntry = KernelLedgerEntry<MessagesFaultKind> & {\n body?: Schema.Json\n model?: string\n stream?: boolean\n maxTokens?: number\n thinking?: Schema.Json\n toolChoice?: Schema.Json\n toolNames: ReadonlyArray<string>\n credentialHeader?: 'x-api-key' | 'authorization'\n anthropicVersion?: string\n anthropicBeta?: string\n scripted?: 'message' | 'error'\n}\n\nconst credentialHeaderOf = (request: Request): 'x-api-key' | 'authorization' | undefined => {\n if ((request.headers.get('x-api-key') ?? '').trim().length > 0) {\n return 'x-api-key'\n }\n\n return bearerPattern.test(request.headers.get('authorization') ?? '')\n ? 'authorization'\n : undefined\n}\n\nconst isPositiveInteger = (value: Schema.Json | undefined): value is number =>\n Predicate.isNumber(value) && Number.isSafeInteger(value) && value > 0\n\n/**\n * Create a Messages emulator from its config. Each call has independent ledger, fault, and\n * script state.\n *\n * Precedence per request: authentication, a supported `anthropic-version`, JSON and request\n * validation (including a positive integer `max_tokens`, and no `thinking` with a forced\n * `tool_choice`), then the first matching fault if it is a `status` fault, then the next\n * scripted turn, then model validation and defaults; a first matching body fault then shapes the\n * body. Only the first matching fault (in insertion order) applies. Credential headers are never\n * recorded, and credential values are never checked or stored.\n */\nexport const makeMessagesEmulator = (config: MessagesEmulatorConfig): MessagesEmulator => {\n const knownModels = [...config.knownModels]\n\n const errorResponse = (status: number, error: MessagesWireError): Response =>\n jsonResponse(status, messagesErrorEnvelope(error))\n\n const invalidRequest = (message: string): Response =>\n errorResponse(400, { type: 'invalid_request_error', message })\n\n const kernel = makeEmulatorKernel({\n routes: config.routes,\n faultSchema: MessagesFault,\n turnSchema: MessagesScriptedTurn,\n newEntry: (base): MutableLedgerEntry => ({ ...base, toolNames: [] }),\n snapshotEntry: (entry): MessagesLedgerEntry => ({ ...entry, toolNames: [...entry.toolNames] }),\n unknownRoute: () =>\n errorResponse(404, { type: 'not_found_error', message: 'Synthetic: no emulated route.' }),\n stateFields: () => ({ knownModels }),\n inputInvalid: config.inputInvalid\n })\n\n const messages = async (\n request: Request,\n entry: MutableLedgerEntry,\n path: string\n ): Promise<Response> => {\n const credentialHeader = credentialHeaderOf(request)\n\n if (credentialHeader === undefined) {\n entry.status = 401\n\n return errorResponse(401, {\n type: 'authentication_error',\n message: 'Synthetic: an x-api-key header or a bearer credential is required.'\n })\n }\n\n entry.credentialHeader = credentialHeader\n\n const version = request.headers.get('anthropic-version')\n const beta = request.headers.get('anthropic-beta')\n\n if (version !== null) entry.anthropicVersion = version\n\n if (beta !== null) entry.anthropicBeta = beta\n\n if (version === null || !supportedAnthropicVersions.includes(version)) {\n entry.status = 400\n\n return invalidRequest(\n version === null\n ? 'Synthetic: the anthropic-version header is required.'\n : 'Synthetic: the anthropic-version header value is not supported.'\n )\n }\n\n const text = await readText(request)\n const json = text === undefined ? undefined : parseJson(text)\n\n if (text === undefined || json === undefined) {\n entry.status = 400\n\n return invalidRequest('Synthetic: the request body is not valid JSON.')\n }\n\n entry.body = json\n\n const decoded = decodeMessagesRequest(json)\n\n if (Result.isFailure(decoded) || !isJsonObject(json)) {\n entry.status = 400\n\n return invalidRequest('Synthetic: the request body is not a Messages request.')\n }\n\n const body = decoded.success\n const seq = entry.seq\n\n if (body.model !== undefined) entry.model = body.model\n\n entry.stream = body.stream === true\n entry.toolNames = (body.tools ?? []).map(tool => tool.name)\n\n if (Predicate.isNumber(body.max_tokens)) entry.maxTokens = body.max_tokens\n\n if (body.thinking !== undefined) entry.thinking = body.thinking\n\n if (body.tool_choice !== undefined) entry.toolChoice = body.tool_choice\n\n const maxTokens = jsonField(json, 'max_tokens')\n\n if (!isPositiveInteger(maxTokens)) {\n entry.status = 400\n\n return invalidRequest('Synthetic: max_tokens must be a positive integer.')\n }\n\n if (thinkingRequested(body) && forcedToolUse(body)) {\n entry.status = 400\n\n return invalidRequest(\n 'Synthetic: thinking may not be enabled when tool_choice forces tool use.'\n )\n }\n\n const fault = kernel.takeFault(path, body.model)\n\n if (fault !== undefined && fault.fault.kind === 'status') {\n return kernel.respondWithStatusFault(entry, fault, fault.fault, defaultFaultBody)\n }\n\n const errorEventFault =\n fault !== undefined && fault.fault.kind === 'error-event-after-chunks'\n ? { state: fault, fault: fault.fault }\n : undefined\n\n const cannotApply = (problem: string): Response => {\n entry.faultError = problem\n entry.status = 500\n\n return controlError(500, `emulator fault cannot apply: ${problem}`)\n }\n\n // A scripted turn is used up when its request arrives. Header and status validation at\n // `script.enqueue` time means its response can always be built.\n const turn = kernel.nextTurn()\n\n if (turn !== undefined && 'error' in turn) {\n entry.scripted = 'error'\n\n if (errorEventFault !== undefined) {\n return cannotApply('error-event-after-chunks cannot apply to a scripted error')\n }\n\n return kernel.respondWithScriptedError(entry, turn.error, fault)\n }\n\n if (turn === undefined && (body.model === undefined || !knownModels.includes(body.model))) {\n entry.status = 404\n\n return errorResponse(404, {\n type: 'not_found_error',\n message: 'Synthetic placeholder: the requested model was not found.'\n })\n }\n\n if (turn !== undefined) entry.scripted = 'message'\n\n const plan = turn === undefined ? defaultPlan(body, seq, maxTokens) : scriptedPlan(turn, seq)\n const identity = { id: `msg_synthetic_${seq}`, model: body.model ?? 'unknown' }\n const usage = planUsage(plan, text)\n\n if (body.stream !== true) {\n if (errorEventFault !== undefined) {\n return cannotApply('error-event-after-chunks cannot apply to a non-streamed response')\n }\n\n return kernel.respondWithBody(\n entry,\n 200,\n { 'content-type': 'application/json' },\n [JSON.stringify(messageBody(plan, identity, usage))],\n fault\n )\n }\n\n const events = streamEvents(plan, identity, usage)\n const headers = { 'content-type': 'text/event-stream', 'cache-control': 'no-cache' }\n\n if (errorEventFault === undefined) {\n return kernel.respondWithBody(entry, 200, headers, events, fault)\n }\n\n const after = errorEventFault.fault.chunks\n\n // The error must arrive before `message_stop`, or a client rightly ignores it.\n if (after >= events.length) {\n return cannotApply(\n `error-event-after-chunks after ${after} chunk(s) cannot apply to a response with ${events.length} chunk(s)`\n )\n }\n\n const response = kernel.respondWithBody(\n entry,\n 200,\n headers,\n [\n ...events.slice(0, after),\n sseEvent('error', { error: { ...(errorEventFault.fault.error ?? defaultErrorEvent) } })\n ],\n undefined\n )\n\n kernel.consumeFault(errorEventFault.state, entry)\n\n return response\n }\n\n // Every manifest route maps to its own handler; construction throws `EmulatorRouteUnmapped`\n // when a manifest route has no handler (or a handler has no manifest route).\n return kernel.serve(new Map([[emulatorRouteKey('POST', config.path), messages]]))\n}\n"],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ import { EmulatorRouteEvidence } from "../route-evidence.mjs";
2
+ import { MicrosoftEmulatorState } from "./state.mjs";
3
+ import { MicrosoftApiEnv, RouteHandler, microsoftEmulatorBasePath } from "./graph.mjs";
4
+ import { Hono } from "@emulators/core";
5
+
6
+ //#region src/microsoft/api.d.ts
7
+ type MicrosoftApiRoute = EmulatorRouteEvidence & {
8
+ /**
9
+ * Query parameters the route emulates; any other key answers 400 before the handler runs, so
10
+ * a rejected request never writes. Empty by default.
11
+ */
12
+ readonly queryKeys: ReadonlyArray<string>; /** `false` only for the copy monitor, a pre-authenticated capability URL. */
13
+ readonly auth: boolean;
14
+ readonly handler: RouteHandler;
15
+ };
16
+ /** The route table: evidence plus handler. `microsoftEmulatorRoutes` is its evidence part. */
17
+ declare const microsoftApiRoutes: ReadonlyArray<MicrosoftApiRoute>;
18
+ type MatchedRoute = {
19
+ readonly route: MicrosoftApiRoute; /** Decoded path parameters. */
20
+ readonly params: Readonly<Record<string, string>>;
21
+ };
22
+ /**
23
+ * The route answering `method` + raw (percent-encoded) `path` with its decoded parameters, or
24
+ * `undefined` (fail closed; also for a parameter that is not valid percent-encoding).
25
+ */
26
+ declare const matchMicrosoftRoute: (method: string, path: string) => MatchedRoute | undefined;
27
+ /** Header the wrapper sets on core requests: the ledger sequence number (for error ids). */
28
+ declare const requestSeqHeader = "x-emulator-request-seq";
29
+ /**
30
+ * The wrapper's fault decision for the core request of job `jobId` (its `emulatorJobHeader`),
31
+ * asked only once the route would answer successfully: `true` when a fault answers instead (it is
32
+ * used up, and the wrapper sends its answer), `false` when none applies.
33
+ */
34
+ type MicrosoftFaultDecision = (jobId: string | null) => boolean;
35
+ /**
36
+ * Register every route of the table on the core app, over the generation's state. Each handler
37
+ * re-matches the raw request path against the same table the wrapper ledgers (so parameters are
38
+ * decoded once, failing closed on invalid percent-encoding), checks the route's query allowlist
39
+ * and refuses `If-Match` (no fixture sends one) before the handler runs, then plans, faults, and
40
+ * commits (see `handle`). A handler that throws answers `handlerFailedResponse()` (nothing
41
+ * written), which the wrapper turns into its Graph error envelope 500 with `responseError` in the
42
+ * ledger.
43
+ */
44
+ declare const registerMicrosoftApi: (app: Hono, state: MicrosoftEmulatorState, env: MicrosoftApiEnv, decideFault: MicrosoftFaultDecision) => void;
45
+ //#endregion
46
+ export { MatchedRoute, MicrosoftFaultDecision, matchMicrosoftRoute, microsoftApiRoutes, microsoftEmulatorBasePath, registerMicrosoftApi, requestSeqHeader };
47
+ //# sourceMappingURL=api.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.mts","names":[],"sources":["../../src/microsoft/api.ts"],"mappings":";;;;;;KAgDK,iBAAA,GAAoB,qBAAA;EAOd;;;;EAAA,SAFA,SAAA,EAAW,aAAA,UAyDT;EAAA,SAvDF,IAAA;EAAA,SACA,OAAA,EAAS,YAAA;AAAA;AAsD4C;AAAA,cAAnD,kBAAA,EAAoB,aAAa,CAAC,iBAAA;AAAA,KAwInC,YAAA;EAAA,SACD,KAAA,EAAO,iBAAA,EAAA;EAAA,SAEP,MAAA,EAAQ,QAAA,CAAS,MAAA;AAAA;;;;;cAOf,mBAAA,GAAuB,MAAA,UAAgB,IAAA,aAAe,YAAY;;cAyBlE,gBAAA;;AAhCqB;AAOlC;;;KAgCY,sBAAA,IAA0B,KAAoB;;;;;AAhCqB;AAyB/E;;;;cAiIa,oBAAA,GACX,GAAA,EAAK,IAAA,EACL,KAAA,EAAO,sBAAA,EACP,GAAA,EAAK,eAAA,EACL,WAAA,EAAa,sBAAA"}