@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,216 @@
1
+ import { Predicate } from "effect";
2
+ //#region src/stateful-secrets.ts
3
+ /**
4
+ * Credential guarding and the fail-closed ledger constants (internal; imported by the stateful
5
+ * wrapper, `src/stateful-emulator.ts`, and by the `src/r2-guard.ts` port guard, which uses only the
6
+ * predicate form of the closure, `textClosureOutcome`, without the shared minimum length). No Node
7
+ * builtin, no core import, and no wrapper import, so the R2 guard imports it without the wrapper.
8
+ *
9
+ * A guarded secret (a request-carried credential value the wrapper extracted from a recognised
10
+ * request shape) must never reach the ledger, a response, or `/_emulate/*`: `scrubSecrets` removes
11
+ * it from everything recorded or answered, and the `*RepeatsSecret` checks find it in request text
12
+ * so a request repeating it can be refused. `repeatsSecret` and `jsonRepeatsSecret` (raw, once
13
+ * percent-decoded, parsed JSON keys, strings, and numbers as JavaScript prints them) serve the
14
+ * wrapper's resolved mode (Todoist, Telegram), unchanged; its fail-closed mode uses
15
+ * `textRepeatsSecret`, the fixpoint closure of two total, lexical transforms that cannot fail
16
+ * (`tolerantPercentDecode`, `tolerantJsonUnescape`), failing closed when its work cap is hit, and
17
+ * recognises only RFC 6750 `b64token` bearers whose first character completes no escape and that
18
+ * lie outside the JSON-number alphabet (`isRecognisableBearerValue`).
19
+ *
20
+ * @experimental
21
+ */
22
+ /** The ledgered path of every unrecognised request (constant: nothing from the request). */
23
+ const unrecognisedLedgerPath = "/<unrecognised>";
24
+ const ledgerableMethods = new Set([
25
+ "GET",
26
+ "HEAD",
27
+ "POST",
28
+ "PUT",
29
+ "PATCH",
30
+ "DELETE",
31
+ "OPTIONS"
32
+ ]);
33
+ /** The ledgered method of an unrecognised request: a standard method, or `<other>`. */
34
+ const unrecognisedMethod = (method) => ledgerableMethods.has(method) ? method : "<other>";
35
+ /** `value` percent-decoded once, or unchanged when it is not valid percent-encoding. */
36
+ const decodedOrRaw = (value) => {
37
+ try {
38
+ return decodeURIComponent(value);
39
+ } catch {
40
+ return value;
41
+ }
42
+ };
43
+ /** Secrets shorter than this are not scrubbed (they would redact ordinary text). */
44
+ const minimumSecretLength = 4;
45
+ const meaningful = (secrets) => secrets.filter((secret) => secret.length >= minimumSecretLength);
46
+ /** True when `text`, raw or percent-decoded, contains a secret. */
47
+ const repeatsSecret = (text, secrets) => {
48
+ const decoded = decodedOrRaw(text.replaceAll("+", " "));
49
+ return meaningful(secrets).some((secret) => text.includes(secret) || decoded.includes(secret));
50
+ };
51
+ const isJsonRecord = (value) => value !== null && Predicate.isObject(value) && !Array.isArray(value);
52
+ /**
53
+ * True when any object key, string value, or number of `value` (raw or percent-decoded) holds a
54
+ * secret. Numbers are checked as JavaScript prints them (`1.2345678e7` parses to `12345678`). Used
55
+ * by the wrapper's resolved mode (Todoist, Telegram), unchanged.
56
+ */
57
+ const jsonRepeatsSecret = (value, secrets) => {
58
+ if (Predicate.isString(value)) return repeatsSecret(value, secrets);
59
+ if (Predicate.isNumber(value)) return repeatsSecret(String(value), secrets);
60
+ if (Array.isArray(value)) return value.some((item) => jsonRepeatsSecret(item, secrets));
61
+ if (isJsonRecord(value)) return Object.entries(value).some(([key, item]) => repeatsSecret(key, secrets) || jsonRepeatsSecret(item, secrets));
62
+ return false;
63
+ };
64
+ /**
65
+ * The JSON-number alphabet. A fail-closed bearer must hold at least one character outside it
66
+ * (`isRecognisableBearerValue`), so no number's text can ever contain or equal it: numeric forms
67
+ * (`1.2345678e7`, any precision) need no normalisation.
68
+ */
69
+ const jsonNumberAlphabet = /^[0-9.eE+-]+$/;
70
+ /**
71
+ * The RFC 6750 `b64token` syntax (`1*( ALPHA / DIGIT / "-" / "." / "_" / "~" / "+" / "/" ) *"="`),
72
+ * at least 8 characters: what every GitHub (`ghp_…`, `github_pat_…`, `gho_…`) and Google (`ya29.…`)
73
+ * token is made of. Why exactly this: it holds no escape introducer the closure's transforms
74
+ * recognise (`%`, `\`, nor `"`), so no escape can start inside a bearer; with `firstCharacter`,
75
+ * no escape starting to its left can complete with its first character either (see there).
76
+ */
77
+ const b64token = /^[A-Za-z0-9\-._~+/]+=*$/;
78
+ /**
79
+ * The first character a fail-closed bearer may start with: `[G-Zg-z\-._~+/]` without the
80
+ * lower-case JSON escape letters `n`, `r`, `t`, `u`. Proof that no neighbour can then hide the
81
+ * bearer:
82
+ *
83
+ * 1. The bearer holds no escape introducer (a `b64token` has no `%`, `\`, or `"`), so no escape
84
+ * the transforms recognise can start inside it.
85
+ * 2. An escape that starts to its left (a stray `%`, `%X`, `\`, `\u`, `\u0`, `\u00`, `\u006`, or
86
+ * such an introducer produced by an earlier round, `%25` or `%5C` decoded) can only reach the
87
+ * bearer by consuming its first character. That character completes no escape form: it is no
88
+ * hex digit (so no `%X`, `%XX`, or `\uXXXX` prefix completes with it) and no short JSON escape
89
+ * letter (`b` and `f` are hex; `n`, `r`, `t`, `u` are excluded). `/` is kept: `\/` decodes to
90
+ * `/`, which leaves the character in place. When the first character is itself escaped, a stray
91
+ * `\` can pair with the escape's leading `\`: the pair `\\` decodes to `\`, followed by the rest
92
+ * of the escape, which decodes in a later step. That delays the decoding but never destroys it,
93
+ * and the closure runs to a fixpoint, so delays do not matter.
94
+ * 3. So the bearer's characters always decode in place, and the closure finds the bearer once its
95
+ * own encodings are undone.
96
+ *
97
+ * Upper-case `N`, `R`, `T`, `U` are allowed: the JSON escape letters are case-sensitive, and
98
+ * `tolerantJsonUnescape` recognises only the lower-case ones (`\N` stays as it is), so they
99
+ * complete no escape either.
100
+ */
101
+ const firstCharacter = /^[G-Zg-mo-qsv-z\-._~+/]/;
102
+ /**
103
+ * True when a bearer value matches the RFC 6750 `b64token` syntax exactly (at least 8
104
+ * characters), starts with a character that completes no escape (`firstCharacter`), and holds a
105
+ * character outside the JSON-number alphabet `[0-9.eE+-]`, so it is never the text of a number
106
+ * and no escape can be shifted across its characters.
107
+ */
108
+ const isRecognisableBearerValue = (value) => value.length >= 8 && b64token.test(value) && firstCharacter.test(value) && !jsonNumberAlphabet.test(value);
109
+ /**
110
+ * The work caps of `textRepeatsSecret`. The closure runs to a fixpoint; these only bound the work
111
+ * of a pathological text, and hitting one counts as a credential repeat (uncertainty refuses, it
112
+ * never admits). Measured margins: every fixture converges in a few rounds and texts; a 64 KiB
113
+ * body of densely nested escapes converges in about 25 rounds, under 100 texts, and about 2.4 Mi
114
+ * characters read; a pathological 64 KiB body hits a cap in about 100 ms. The character cap is
115
+ * spent on reading too, so any part over 4 Mi characters is always refused, escapes or not (far
116
+ * above GitHub's 65 536-character body limit).
117
+ */
118
+ const secretClosureCaps = {
119
+ /** Rounds of the breadth-first walk. */
120
+ rounds: 64,
121
+ /** Distinct texts seen. */
122
+ texts: 1024,
123
+ /** Characters the transforms read, over all texts (keeps the worst large body near 100 ms). */
124
+ characters: 8 * 1024 * 1024
125
+ };
126
+ /**
127
+ * Tolerant percent-decode, total: every `%XX` whose value is below `0x80` becomes its ASCII
128
+ * character; every other `%` sequence (a stray `%`, `%E9`, `%zz`) is left as it is. It never
129
+ * throws, so an encoded fragment next to `100%` or `%E9` is still decoded.
130
+ */
131
+ const tolerantPercentDecode = (text) => !text.includes("%") ? text : text.replace(/%([0-7][0-9A-Fa-f])/g, (_escape, hex) => String.fromCharCode(Number.parseInt(hex, 16)));
132
+ /** The short JSON escapes and the characters they stand for. */
133
+ const jsonEscapes = new Map([
134
+ ["\"", "\""],
135
+ ["\\", "\\"],
136
+ ["/", "/"],
137
+ ["b", "\b"],
138
+ ["f", "\f"],
139
+ ["n", "\n"],
140
+ ["r", "\r"],
141
+ ["t", " "]
142
+ ]);
143
+ /**
144
+ * Tolerant JSON-unescape, total and lexical: within any text, whether or not it parses as JSON,
145
+ * `\uXXXX` below `\u0080` and `\"`, `\\`, `\/`, `\b`, `\f`, `\n`, `\r`, `\t` become their
146
+ * characters (one left-to-right pass); every other sequence is left as it is. Being lexical, it
147
+ * sees every string of a JSON text, duplicate keys and overwritten values included.
148
+ */
149
+ const tolerantJsonUnescape = (text) => !text.includes("\\") ? text : text.replace(/\\(?:u([0-9A-Fa-f]{4})|(["\\/bfnrt]))/g, (escape, hex, short) => {
150
+ if (hex !== void 0) {
151
+ const code = Number.parseInt(hex, 16);
152
+ return code < 128 ? String.fromCharCode(code) : escape;
153
+ }
154
+ return jsonEscapes.get(short ?? "") ?? escape;
155
+ });
156
+ /**
157
+ * The closure of `text` against a predicate: starting from the raw text, a breadth-first walk
158
+ * applying either total transform (`tolerantPercentDecode`, `tolerantJsonUnescape`) to every text
159
+ * of the previous round, deduplicated, until no new text appears (a fixpoint); every text is
160
+ * tested with `matches`. Both transforms never lengthen a text and strictly shorten it when they
161
+ * change it, so every branch ends. `capped` when a cap of `secretClosureCaps` is hit first. No
162
+ * JSON is parsed and nothing can fail (unless `matches` throws).
163
+ */
164
+ const textClosureOutcome = (text, matches) => {
165
+ const seen = new Set([text]);
166
+ let characters = 0;
167
+ let frontier = [text];
168
+ for (let round = 0; frontier.length > 0; round += 1) {
169
+ if (frontier.some(matches)) return "matches";
170
+ if (round === secretClosureCaps.rounds) return "capped";
171
+ const next = [];
172
+ for (const candidate of frontier) {
173
+ characters += 2 * candidate.length;
174
+ if (characters > secretClosureCaps.characters) return "capped";
175
+ for (const transformed of [tolerantPercentDecode(candidate), tolerantJsonUnescape(candidate)]) {
176
+ if (seen.has(transformed)) continue;
177
+ if (seen.size >= secretClosureCaps.texts) return "capped";
178
+ seen.add(transformed);
179
+ next.push(transformed);
180
+ }
181
+ }
182
+ frontier = next;
183
+ }
184
+ return "clear";
185
+ };
186
+ /**
187
+ * The closure of `text` against `secrets` (`textClosureOutcome`, every text checked for a secret
188
+ * as a substring). Numbers need no handling: a recognisable bearer never fits the JSON-number
189
+ * alphabet.
190
+ */
191
+ const secretClosureOutcome = (text, secrets) => {
192
+ const guarded = meaningful(secrets);
193
+ if (guarded.length === 0) return "clear";
194
+ const outcome = textClosureOutcome(text, (candidate) => guarded.some((secret) => candidate.includes(secret)));
195
+ return outcome === "matches" ? "repeats" : outcome;
196
+ };
197
+ /**
198
+ * True when `text` repeats a secret anywhere in its closure (`secretClosureOutcome`), or when the
199
+ * closure hits a work cap before its fixpoint: fail closed, uncertainty counts as a repeat.
200
+ */
201
+ const textRepeatsSecret = (text, secrets) => secretClosureOutcome(text, secrets) !== "clear";
202
+ /**
203
+ * `text` with every secret (raw and percent-encoded) replaced by `<redacted>`; when a secret still
204
+ * shows after that (for example in another percent-encoding), the whole text is `<redacted>`.
205
+ * Applied to everything the ledger keeps or a refusal answers.
206
+ */
207
+ const scrubSecrets = (text, secrets) => {
208
+ const variants = meaningful(secrets).flatMap((secret) => [secret, encodeURIComponent(secret)]).sort((left, right) => right.length - left.length);
209
+ let result = text;
210
+ for (const variant of variants) result = result.replaceAll(variant, "<redacted>");
211
+ return repeatsSecret(result, secrets) ? "<redacted>" : result;
212
+ };
213
+ //#endregion
214
+ export { decodedOrRaw, isRecognisableBearerValue, jsonRepeatsSecret, repeatsSecret, scrubSecrets, secretClosureCaps, secretClosureOutcome, textClosureOutcome, textRepeatsSecret, tolerantJsonUnescape, tolerantPercentDecode, unrecognisedLedgerPath, unrecognisedMethod };
215
+
216
+ //# sourceMappingURL=stateful-secrets.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stateful-secrets.mjs","names":[],"sources":["../src/stateful-secrets.ts"],"sourcesContent":["/**\n * Credential guarding and the fail-closed ledger constants (internal; imported by the stateful\n * wrapper, `src/stateful-emulator.ts`, and by the `src/r2-guard.ts` port guard, which uses only the\n * predicate form of the closure, `textClosureOutcome`, without the shared minimum length). No Node\n * builtin, no core import, and no wrapper import, so the R2 guard imports it without the wrapper.\n *\n * A guarded secret (a request-carried credential value the wrapper extracted from a recognised\n * request shape) must never reach the ledger, a response, or `/_emulate/*`: `scrubSecrets` removes\n * it from everything recorded or answered, and the `*RepeatsSecret` checks find it in request text\n * so a request repeating it can be refused. `repeatsSecret` and `jsonRepeatsSecret` (raw, once\n * percent-decoded, parsed JSON keys, strings, and numbers as JavaScript prints them) serve the\n * wrapper's resolved mode (Todoist, Telegram), unchanged; its fail-closed mode uses\n * `textRepeatsSecret`, the fixpoint closure of two total, lexical transforms that cannot fail\n * (`tolerantPercentDecode`, `tolerantJsonUnescape`), failing closed when its work cap is hit, and\n * recognises only RFC 6750 `b64token` bearers whose first character completes no escape and that\n * lie outside the JSON-number alphabet (`isRecognisableBearerValue`).\n *\n * @experimental\n */\nimport { Predicate } from 'effect'\nimport type * as Schema from 'effect/Schema'\n\n/** The ledgered path of every unrecognised request (constant: nothing from the request). */\nexport const unrecognisedLedgerPath = '/<unrecognised>'\n\nconst ledgerableMethods: ReadonlySet<string> = new Set([\n 'GET',\n 'HEAD',\n 'POST',\n 'PUT',\n 'PATCH',\n 'DELETE',\n 'OPTIONS'\n])\n\n/** The ledgered method of an unrecognised request: a standard method, or `<other>`. */\nexport const unrecognisedMethod = (method: string): string =>\n ledgerableMethods.has(method) ? method : '<other>'\n\n/** `value` percent-decoded once, or unchanged when it is not valid percent-encoding. */\nexport const decodedOrRaw = (value: string): string => {\n try {\n return decodeURIComponent(value)\n } catch {\n return value\n }\n}\n\n/** Secrets shorter than this are not scrubbed (they would redact ordinary text). */\nconst minimumSecretLength = 4\n\nconst meaningful = (secrets: ReadonlyArray<string>): ReadonlyArray<string> =>\n secrets.filter(secret => secret.length >= minimumSecretLength)\n\n/** True when `text`, raw or percent-decoded, contains a secret. */\nexport const repeatsSecret = (text: string, secrets: ReadonlyArray<string>): boolean => {\n const decoded = decodedOrRaw(text.replaceAll('+', ' '))\n\n return meaningful(secrets).some(secret => text.includes(secret) || decoded.includes(secret))\n}\n\nconst isJsonRecord = (value: Schema.Json): value is Schema.JsonObject =>\n value !== null && Predicate.isObject(value) && !Array.isArray(value)\n\n/**\n * True when any object key, string value, or number of `value` (raw or percent-decoded) holds a\n * secret. Numbers are checked as JavaScript prints them (`1.2345678e7` parses to `12345678`). Used\n * by the wrapper's resolved mode (Todoist, Telegram), unchanged.\n */\nexport const jsonRepeatsSecret = (value: Schema.Json, secrets: ReadonlyArray<string>): boolean => {\n if (Predicate.isString(value)) return repeatsSecret(value, secrets)\n\n if (Predicate.isNumber(value)) return repeatsSecret(String(value), secrets)\n\n if (Array.isArray(value)) return value.some(item => jsonRepeatsSecret(item, secrets))\n\n if (isJsonRecord(value)) {\n return Object.entries(value).some(\n ([key, item]) => repeatsSecret(key, secrets) || jsonRepeatsSecret(item, secrets)\n )\n }\n\n return false\n}\n\n/**\n * The JSON-number alphabet. A fail-closed bearer must hold at least one character outside it\n * (`isRecognisableBearerValue`), so no number's text can ever contain or equal it: numeric forms\n * (`1.2345678e7`, any precision) need no normalisation.\n */\nconst jsonNumberAlphabet = /^[0-9.eE+-]+$/\n\n/**\n * The RFC 6750 `b64token` syntax (`1*( ALPHA / DIGIT / \"-\" / \".\" / \"_\" / \"~\" / \"+\" / \"/\" ) *\"=\"`),\n * at least 8 characters: what every GitHub (`ghp_…`, `github_pat_…`, `gho_…`) and Google (`ya29.…`)\n * token is made of. Why exactly this: it holds no escape introducer the closure's transforms\n * recognise (`%`, `\\`, nor `\"`), so no escape can start inside a bearer; with `firstCharacter`,\n * no escape starting to its left can complete with its first character either (see there).\n */\nconst b64token = /^[A-Za-z0-9\\-._~+/]+=*$/\n\n/**\n * The first character a fail-closed bearer may start with: `[G-Zg-z\\-._~+/]` without the\n * lower-case JSON escape letters `n`, `r`, `t`, `u`. Proof that no neighbour can then hide the\n * bearer:\n *\n * 1. The bearer holds no escape introducer (a `b64token` has no `%`, `\\`, or `\"`), so no escape\n * the transforms recognise can start inside it.\n * 2. An escape that starts to its left (a stray `%`, `%X`, `\\`, `\\u`, `\\u0`, `\\u00`, `\\u006`, or\n * such an introducer produced by an earlier round, `%25` or `%5C` decoded) can only reach the\n * bearer by consuming its first character. That character completes no escape form: it is no\n * hex digit (so no `%X`, `%XX`, or `\\uXXXX` prefix completes with it) and no short JSON escape\n * letter (`b` and `f` are hex; `n`, `r`, `t`, `u` are excluded). `/` is kept: `\\/` decodes to\n * `/`, which leaves the character in place. When the first character is itself escaped, a stray\n * `\\` can pair with the escape's leading `\\`: the pair `\\\\` decodes to `\\`, followed by the rest\n * of the escape, which decodes in a later step. That delays the decoding but never destroys it,\n * and the closure runs to a fixpoint, so delays do not matter.\n * 3. So the bearer's characters always decode in place, and the closure finds the bearer once its\n * own encodings are undone.\n *\n * Upper-case `N`, `R`, `T`, `U` are allowed: the JSON escape letters are case-sensitive, and\n * `tolerantJsonUnescape` recognises only the lower-case ones (`\\N` stays as it is), so they\n * complete no escape either.\n */\nconst firstCharacter = /^[G-Zg-mo-qsv-z\\-._~+/]/\n\n/**\n * True when a bearer value matches the RFC 6750 `b64token` syntax exactly (at least 8\n * characters), starts with a character that completes no escape (`firstCharacter`), and holds a\n * character outside the JSON-number alphabet `[0-9.eE+-]`, so it is never the text of a number\n * and no escape can be shifted across its characters.\n */\nexport const isRecognisableBearerValue = (value: string): boolean =>\n value.length >= 8 &&\n b64token.test(value) &&\n firstCharacter.test(value) &&\n !jsonNumberAlphabet.test(value)\n\n/**\n * The work caps of `textRepeatsSecret`. The closure runs to a fixpoint; these only bound the work\n * of a pathological text, and hitting one counts as a credential repeat (uncertainty refuses, it\n * never admits). Measured margins: every fixture converges in a few rounds and texts; a 64 KiB\n * body of densely nested escapes converges in about 25 rounds, under 100 texts, and about 2.4 Mi\n * characters read; a pathological 64 KiB body hits a cap in about 100 ms. The character cap is\n * spent on reading too, so any part over 4 Mi characters is always refused, escapes or not (far\n * above GitHub's 65 536-character body limit).\n */\nexport const secretClosureCaps = {\n /** Rounds of the breadth-first walk. */\n rounds: 64,\n /** Distinct texts seen. */\n texts: 1024,\n /** Characters the transforms read, over all texts (keeps the worst large body near 100 ms). */\n characters: 8 * 1024 * 1024\n} as const\n\n/**\n * Tolerant percent-decode, total: every `%XX` whose value is below `0x80` becomes its ASCII\n * character; every other `%` sequence (a stray `%`, `%E9`, `%zz`) is left as it is. It never\n * throws, so an encoded fragment next to `100%` or `%E9` is still decoded.\n */\nexport const tolerantPercentDecode = (text: string): string =>\n !text.includes('%')\n ? text\n : text.replace(/%([0-7][0-9A-Fa-f])/g, (_escape, hex: string) =>\n String.fromCharCode(Number.parseInt(hex, 16))\n )\n\n/** The short JSON escapes and the characters they stand for. */\nconst jsonEscapes = new Map([\n ['\"', '\"'],\n ['\\\\', '\\\\'],\n ['/', '/'],\n ['b', '\\b'],\n ['f', '\\f'],\n ['n', '\\n'],\n ['r', '\\r'],\n ['t', '\\t']\n])\n\n/**\n * Tolerant JSON-unescape, total and lexical: within any text, whether or not it parses as JSON,\n * `\\uXXXX` below `\\u0080` and `\\\"`, `\\\\`, `\\/`, `\\b`, `\\f`, `\\n`, `\\r`, `\\t` become their\n * characters (one left-to-right pass); every other sequence is left as it is. Being lexical, it\n * sees every string of a JSON text, duplicate keys and overwritten values included.\n */\nexport const tolerantJsonUnescape = (text: string): string =>\n !text.includes('\\\\')\n ? text\n : text.replace(\n /\\\\(?:u([0-9A-Fa-f]{4})|([\"\\\\/bfnrt]))/g,\n (escape, hex?: string, short?: string) => {\n if (hex !== undefined) {\n const code = Number.parseInt(hex, 16)\n\n return code < 0x80 ? String.fromCharCode(code) : escape\n }\n\n return jsonEscapes.get(short ?? '') ?? escape\n }\n )\n\n/** What the closure of a text found: the secret, its fixpoint without the secret, or a cap. */\nexport type SecretClosureOutcome = 'repeats' | 'clear' | 'capped'\n\n/** What the closure of a text found: a matching text, its fixpoint without one, or a cap. */\nexport type TextClosureOutcome = 'matches' | 'clear' | 'capped'\n\n/**\n * The closure of `text` against a predicate: starting from the raw text, a breadth-first walk\n * applying either total transform (`tolerantPercentDecode`, `tolerantJsonUnescape`) to every text\n * of the previous round, deduplicated, until no new text appears (a fixpoint); every text is\n * tested with `matches`. Both transforms never lengthen a text and strictly shorten it when they\n * change it, so every branch ends. `capped` when a cap of `secretClosureCaps` is hit first. No\n * JSON is parsed and nothing can fail (unless `matches` throws).\n */\nexport const textClosureOutcome = (\n text: string,\n matches: (candidate: string) => boolean\n): TextClosureOutcome => {\n const seen = new Set([text])\n let characters = 0\n let frontier: ReadonlyArray<string> = [text]\n\n for (let round = 0; frontier.length > 0; round += 1) {\n if (frontier.some(matches)) return 'matches'\n\n if (round === secretClosureCaps.rounds) return 'capped'\n\n const next: Array<string> = []\n\n for (const candidate of frontier) {\n // The work: every character each transform reads.\n characters += 2 * candidate.length\n\n if (characters > secretClosureCaps.characters) return 'capped'\n\n for (const transformed of [\n tolerantPercentDecode(candidate),\n tolerantJsonUnescape(candidate)\n ]) {\n if (seen.has(transformed)) continue\n\n if (seen.size >= secretClosureCaps.texts) return 'capped'\n\n seen.add(transformed)\n next.push(transformed)\n }\n }\n\n frontier = next\n }\n\n return 'clear'\n}\n\n/**\n * The closure of `text` against `secrets` (`textClosureOutcome`, every text checked for a secret\n * as a substring). Numbers need no handling: a recognisable bearer never fits the JSON-number\n * alphabet.\n */\nexport const secretClosureOutcome = (\n text: string,\n secrets: ReadonlyArray<string>\n): SecretClosureOutcome => {\n const guarded = meaningful(secrets)\n\n if (guarded.length === 0) return 'clear'\n\n const outcome = textClosureOutcome(text, candidate =>\n guarded.some(secret => candidate.includes(secret))\n )\n\n return outcome === 'matches' ? 'repeats' : outcome\n}\n\n/**\n * True when `text` repeats a secret anywhere in its closure (`secretClosureOutcome`), or when the\n * closure hits a work cap before its fixpoint: fail closed, uncertainty counts as a repeat.\n */\nexport const textRepeatsSecret = (text: string, secrets: ReadonlyArray<string>): boolean =>\n secretClosureOutcome(text, secrets) !== 'clear'\n\n/**\n * `text` with every secret (raw and percent-encoded) replaced by `<redacted>`; when a secret still\n * shows after that (for example in another percent-encoding), the whole text is `<redacted>`.\n * Applied to everything the ledger keeps or a refusal answers.\n */\nexport const scrubSecrets = (text: string, secrets: ReadonlyArray<string>): string => {\n const variants = meaningful(secrets)\n .flatMap(secret => [secret, encodeURIComponent(secret)])\n .sort((left, right) => right.length - left.length)\n\n let result = text\n\n for (const variant of variants) result = result.replaceAll(variant, '<redacted>')\n\n return repeatsSecret(result, secrets) ? '<redacted>' : result\n}\n"],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { FixtureRecording } from "./fixture-route.mjs";
2
+
3
+ //#region src/subscription-usage-recordings.d.ts
4
+ declare const anthropicClaudeUsageRecording: FixtureRecording;
5
+ declare const codexUsageRecording: FixtureRecording;
6
+ declare const xAiGrokUsageRecording: FixtureRecording;
7
+ //#endregion
8
+ export { anthropicClaudeUsageRecording, codexUsageRecording, xAiGrokUsageRecording };
9
+ //# sourceMappingURL=subscription-usage-recordings.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscription-usage-recordings.d.mts","names":[],"sources":["../src/subscription-usage-recordings.ts"],"mappings":";;;cASa,6BAAA,EAA+B,gBAqB3C;AAAA,cAEY,mBAAA,EAAqB,gBAqBjC;AAAA,cAEY,qBAAA,EAAuB,gBAqBnC"}
@@ -0,0 +1,53 @@
1
+ //#region src/subscription-usage-recordings.ts
2
+ const anthropicClaudeUsageRecording = {
3
+ fixtureId: "anthropic.claude.usage.snapshot.synthetic",
4
+ caseId: "anthropic.claude.usage.snapshot",
5
+ request: {
6
+ method: "GET",
7
+ path: "/api/oauth/usage",
8
+ query: "",
9
+ headers: { accept: "application/json" }
10
+ },
11
+ response: {
12
+ status: 200,
13
+ headers: { "content-type": "application/json" },
14
+ streamed: false,
15
+ chunks: ["{\"five_hour\":{\"utilization\":18,\"resets_at\":\"2026-10-01T05:00:00.000Z\"},\"seven_day\":{\"utilization\":42,\"resets_at\":\"2026-10-06T00:00:00.000Z\"}}"]
16
+ }
17
+ };
18
+ const codexUsageRecording = {
19
+ fixtureId: "openai.codex.usage.snapshot.synthetic",
20
+ caseId: "openai.codex.usage.snapshot",
21
+ request: {
22
+ method: "GET",
23
+ path: "/backend-api/wham/usage",
24
+ query: "",
25
+ headers: { accept: "application/json" }
26
+ },
27
+ response: {
28
+ status: 200,
29
+ headers: { "content-type": "application/json" },
30
+ streamed: false,
31
+ chunks: ["{\"rate_limit\":{\"primary_window\":{\"used_percent\":23,\"limit_window_seconds\":18000,\"reset_after_seconds\":7200,\"reset_at\":1790007200},\"secondary_window\":{\"used_percent\":51,\"limit_window_seconds\":604800,\"reset_after_seconds\":259200,\"reset_at\":1790259200}}}"]
32
+ }
33
+ };
34
+ const xAiGrokUsageRecording = {
35
+ fixtureId: "xai.grok.usage.snapshot.synthetic",
36
+ caseId: "xai.grok.usage.snapshot",
37
+ request: {
38
+ method: "GET",
39
+ path: "/v1/billing",
40
+ query: "?format=credits",
41
+ headers: { accept: "application/json" }
42
+ },
43
+ response: {
44
+ status: 200,
45
+ headers: { "content-type": "application/json" },
46
+ streamed: false,
47
+ chunks: ["{\"config\":{\"creditUsagePercent\":37.5,\"currentPeriod\":{\"type\":\"monthly\",\"start\":\"2026-09-01T00:00:00.000Z\",\"end\":\"2026-10-01T00:00:00.000Z\"}}}"]
48
+ }
49
+ };
50
+ //#endregion
51
+ export { anthropicClaudeUsageRecording, codexUsageRecording, xAiGrokUsageRecording };
52
+
53
+ //# sourceMappingURL=subscription-usage-recordings.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscription-usage-recordings.mjs","names":[],"sources":["../src/subscription-usage-recordings.ts"],"sourcesContent":["/**\n * Subscription-usage recordings the `/anthropic`, `/codex`, and `/xai` usage routes answer from.\n *\n * Copied as data from the committed (synthetic, unverified) conformance fixtures; never imported.\n * `test/fixture-recordings.test.ts` fails when a fixture changes and this copy does not. Internal;\n * not a package export.\n */\nimport type { FixtureRecording } from './fixture-route.ts'\n\nexport const anthropicClaudeUsageRecording: FixtureRecording = {\n fixtureId: 'anthropic.claude.usage.snapshot.synthetic',\n caseId: 'anthropic.claude.usage.snapshot',\n request: {\n method: 'GET',\n path: '/api/oauth/usage',\n query: '',\n headers: {\n accept: 'application/json'\n }\n },\n response: {\n status: 200,\n headers: {\n 'content-type': 'application/json'\n },\n streamed: false,\n chunks: [\n '{\"five_hour\":{\"utilization\":18,\"resets_at\":\"2026-10-01T05:00:00.000Z\"},\"seven_day\":{\"utilization\":42,\"resets_at\":\"2026-10-06T00:00:00.000Z\"}}'\n ]\n }\n}\n\nexport const codexUsageRecording: FixtureRecording = {\n fixtureId: 'openai.codex.usage.snapshot.synthetic',\n caseId: 'openai.codex.usage.snapshot',\n request: {\n method: 'GET',\n path: '/backend-api/wham/usage',\n query: '',\n headers: {\n accept: 'application/json'\n }\n },\n response: {\n status: 200,\n headers: {\n 'content-type': 'application/json'\n },\n streamed: false,\n chunks: [\n '{\"rate_limit\":{\"primary_window\":{\"used_percent\":23,\"limit_window_seconds\":18000,\"reset_after_seconds\":7200,\"reset_at\":1790007200},\"secondary_window\":{\"used_percent\":51,\"limit_window_seconds\":604800,\"reset_after_seconds\":259200,\"reset_at\":1790259200}}}'\n ]\n }\n}\n\nexport const xAiGrokUsageRecording: FixtureRecording = {\n fixtureId: 'xai.grok.usage.snapshot.synthetic',\n caseId: 'xai.grok.usage.snapshot',\n request: {\n method: 'GET',\n path: '/v1/billing',\n query: '?format=credits',\n headers: {\n accept: 'application/json'\n }\n },\n response: {\n status: 200,\n headers: {\n 'content-type': 'application/json'\n },\n streamed: false,\n chunks: [\n '{\"config\":{\"creditUsagePercent\":37.5,\"currentPeriod\":{\"type\":\"monthly\",\"start\":\"2026-09-01T00:00:00.000Z\",\"end\":\"2026-10-01T00:00:00.000Z\"}}}'\n ]\n }\n}\n"],"mappings":";AASA,MAAa,gCAAkD;CAC7D,WAAW;CACX,QAAQ;CACR,SAAS;EACP,QAAQ;EACR,MAAM;EACN,OAAO;EACP,SAAS,EACP,QAAQ,mBACV;CACF;CACA,UAAU;EACR,QAAQ;EACR,SAAS,EACP,gBAAgB,mBAClB;EACA,UAAU;EACV,QAAQ,CACN,+JACF;CACF;AACF;AAEA,MAAa,sBAAwC;CACnD,WAAW;CACX,QAAQ;CACR,SAAS;EACP,QAAQ;EACR,MAAM;EACN,OAAO;EACP,SAAS,EACP,QAAQ,mBACV;CACF;CACA,UAAU;EACR,QAAQ;EACR,SAAS,EACP,gBAAgB,mBAClB;EACA,UAAU;EACV,QAAQ,CACN,mRACF;CACF;AACF;AAEA,MAAa,wBAA0C;CACrD,WAAW;CACX,QAAQ;CACR,SAAS;EACP,QAAQ;EACR,MAAM;EACN,OAAO;EACP,SAAS,EACP,QAAQ,mBACV;CACF;CACA,UAAU;EACR,QAAQ;EACR,SAAS,EACP,gBAAgB,mBAClB;EACA,UAAU;EACV,QAAQ,CACN,iKACF;CACF;AACF"}
@@ -0,0 +1,53 @@
1
+ import { EmulatorRouteEvidence } from "./route-evidence.mjs";
2
+ import { FixtureRecording, FixtureRouteEmulator, FixtureRouteFault, FixtureRouteFaultKind, FixtureRouteHeaderRule, FixtureRouteLedgerEntry, FixtureRouteScriptedTurn } from "./fixture-route.mjs";
3
+ import * as Schema from "effect/Schema";
4
+
5
+ //#region src/subscription-usage.d.ts
6
+ /** Usage-route faults: `status`, `error-after-chunks`, `truncate-after-chunks` (one-chunk body). */
7
+ declare const SubscriptionUsageFault: Schema.Union<readonly [Schema.Struct<{
8
+ readonly status: Schema.Int;
9
+ readonly match: Schema.optionalKey<Schema.Struct<{
10
+ readonly path: Schema.optionalKey<Schema.String>;
11
+ readonly model: Schema.optionalKey<Schema.String>;
12
+ }>>;
13
+ readonly count: Schema.optionalKey<Schema.Int>;
14
+ readonly kind: Schema.Literal<"status">;
15
+ readonly headers: Schema.optionalKey<Schema.$Record<Schema.String, Schema.String>>;
16
+ readonly body: Schema.optionalKey<Schema.Codec<Schema.Json, Schema.Json, never, never>>;
17
+ }>, Schema.Struct<{
18
+ readonly match: Schema.optionalKey<Schema.Struct<{
19
+ readonly path: Schema.optionalKey<Schema.String>;
20
+ readonly model: Schema.optionalKey<Schema.String>;
21
+ }>>;
22
+ readonly count: Schema.optionalKey<Schema.Int>;
23
+ readonly kind: Schema.Literal<"error-after-chunks">;
24
+ readonly chunks: Schema.Int;
25
+ }>, Schema.Struct<{
26
+ readonly match: Schema.optionalKey<Schema.Struct<{
27
+ readonly path: Schema.optionalKey<Schema.String>;
28
+ readonly model: Schema.optionalKey<Schema.String>;
29
+ }>>;
30
+ readonly count: Schema.optionalKey<Schema.Int>;
31
+ readonly kind: Schema.Literal<"truncate-after-chunks">;
32
+ readonly chunks: Schema.Int;
33
+ }>]>;
34
+ type SubscriptionUsageFault = FixtureRouteFault;
35
+ type SubscriptionUsageFaultKind = FixtureRouteFaultKind;
36
+ /** A usage turn: `{ usage }` (a body with the recorded JSON shape) or `{ error }`. */
37
+ type SubscriptionUsageScriptedTurn = FixtureRouteScriptedTurn;
38
+ type SubscriptionUsageLedgerEntry = FixtureRouteLedgerEntry;
39
+ type SubscriptionUsageEmulator = FixtureRouteEmulator;
40
+ type SubscriptionUsageEmulatorConfig = {
41
+ readonly path: string;
42
+ readonly routes: ReadonlyArray<EmulatorRouteEvidence>;
43
+ readonly recording: FixtureRecording; /** Headers the SDK fetcher sends besides `Authorization: Bearer` and `accept`, in order. */
44
+ readonly headers: ReadonlyArray<FixtureRouteHeaderRule>; /** Replacement default body; must have the recorded JSON shape. */
45
+ readonly subscriptionUsage: Schema.Json | undefined;
46
+ readonly inputInvalid: (input: 'fault' | 'turn', reason: string) => Error;
47
+ };
48
+ /** The recorded snapshot body of a usage recording, parsed. */
49
+ declare const recordedUsageBody: (recording: FixtureRecording) => Schema.Json;
50
+ declare const makeSubscriptionUsageEmulator: (config: SubscriptionUsageEmulatorConfig) => SubscriptionUsageEmulator;
51
+ //#endregion
52
+ export { SubscriptionUsageEmulator, SubscriptionUsageEmulatorConfig, SubscriptionUsageFault, SubscriptionUsageFaultKind, SubscriptionUsageLedgerEntry, SubscriptionUsageScriptedTurn, makeSubscriptionUsageEmulator, recordedUsageBody };
53
+ //# sourceMappingURL=subscription-usage.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscription-usage.d.mts","names":[],"sources":["../src/subscription-usage.ts"],"mappings":";;;;;;cA2Ba,sBAAA,EAAsB,MAAA,CAAA,KAAA,WAAA,MAAA,CAAA,MAAA;EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;KAEvB,sBAAA,GAAyB,iBAAiB;AAAA,KAE1C,0BAAA,GAA6B,qBAAqB;;KAGlD,6BAAA,GAAgC,wBAAwB;AAAA,KAExD,4BAAA,GAA+B,uBAAuB;AAAA,KAEtD,yBAAA,GAA4B,oBAAoB;AAAA,KAEhD,+BAAA;EAAA,SACD,IAAA;EAAA,SACA,MAAA,EAAQ,aAAA,CAAc,qBAAA;EAAA,SACtB,SAAA,EAAW,gBAAA,EAhBa;EAAA,SAkBxB,OAAA,EAAS,aAAA,CAAc,sBAAA,GAlBC;EAAA,SAoBxB,iBAAA,EAAmB,MAAA,CAAO,IAAA;EAAA,SAC1B,YAAA,GAAe,KAAA,oBAAyB,MAAA,aAAmB,KAAA;AAAA;;cAIzD,iBAAA,GAAqB,SAAA,EAAW,gBAAA,KAAmB,MAAA,CAAO,IAChB;AAAA,cAE1C,6BAAA,GACX,MAAA,EAAQ,+BAAA,KACP,yBAUC"}
@@ -0,0 +1,21 @@
1
+ import { parseJson } from "./emulator-kernel.mjs";
2
+ import { FixtureRouteFault, makeFixtureRouteEmulator } from "./fixture-route.mjs";
3
+ //#region src/subscription-usage.ts
4
+ /** Usage-route faults: `status`, `error-after-chunks`, `truncate-after-chunks` (one-chunk body). */
5
+ const SubscriptionUsageFault = FixtureRouteFault;
6
+ /** The recorded snapshot body of a usage recording, parsed. */
7
+ const recordedUsageBody = (recording) => parseJson(recording.response.chunks.join("")) ?? null;
8
+ const makeSubscriptionUsageEmulator = (config) => makeFixtureRouteEmulator({
9
+ method: "GET",
10
+ path: config.path,
11
+ routes: config.routes,
12
+ recordings: [config.recording],
13
+ credential: "bearer",
14
+ headers: config.headers,
15
+ replaceableBody: { defaultBody: config.subscriptionUsage },
16
+ inputInvalid: config.inputInvalid
17
+ });
18
+ //#endregion
19
+ export { SubscriptionUsageFault, makeSubscriptionUsageEmulator, recordedUsageBody };
20
+
21
+ //# sourceMappingURL=subscription-usage.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscription-usage.mjs","names":[],"sources":["../src/subscription-usage.ts"],"sourcesContent":["/**\n * Subscription-usage routes (internal; not a package export): one `GET` route per usage endpoint\n * the SDK fetchers call (Claude, Codex, Grok, OpenCode Go), on the fixture-only core\n * (`fixture-route.ts`). A request carrying the credential and headers the fetcher sends, on the\n * recorded query, gets the recorded snapshot body; everything else answers 400 not-emulated. The\n * body may be replaced (`subscriptionUsage` option, scripted `{ usage }` turn) only by a body with\n * the recorded JSON shape.\n *\n * Usage routes live next to a model route on the same origin (`/anthropic`, `/codex`, `/xai`,\n * `/opencode`), but keep their own manifest, ledger, faults, and turns, so the model route's\n * manifest and coverage are unchanged; `emulator-compose.ts` dispatches to them.\n */\nimport type * as Schema from 'effect/Schema'\nimport {\n FixtureRouteFault,\n makeFixtureRouteEmulator,\n type FixtureRecording,\n type FixtureRouteEmulator,\n type FixtureRouteFaultKind,\n type FixtureRouteHeaderRule,\n type FixtureRouteLedgerEntry,\n type FixtureRouteScriptedTurn\n} from './fixture-route.ts'\nimport { parseJson } from './emulator-kernel.ts'\nimport type { EmulatorRouteEvidence } from './route-evidence.ts'\n\n/** Usage-route faults: `status`, `error-after-chunks`, `truncate-after-chunks` (one-chunk body). */\nexport const SubscriptionUsageFault = FixtureRouteFault\n\nexport type SubscriptionUsageFault = FixtureRouteFault\n\nexport type SubscriptionUsageFaultKind = FixtureRouteFaultKind\n\n/** A usage turn: `{ usage }` (a body with the recorded JSON shape) or `{ error }`. */\nexport type SubscriptionUsageScriptedTurn = FixtureRouteScriptedTurn\n\nexport type SubscriptionUsageLedgerEntry = FixtureRouteLedgerEntry\n\nexport type SubscriptionUsageEmulator = FixtureRouteEmulator\n\nexport type SubscriptionUsageEmulatorConfig = {\n readonly path: string\n readonly routes: ReadonlyArray<EmulatorRouteEvidence>\n readonly recording: FixtureRecording\n /** Headers the SDK fetcher sends besides `Authorization: Bearer` and `accept`, in order. */\n readonly headers: ReadonlyArray<FixtureRouteHeaderRule>\n /** Replacement default body; must have the recorded JSON shape. */\n readonly subscriptionUsage: Schema.Json | undefined\n readonly inputInvalid: (input: 'fault' | 'turn', reason: string) => Error\n}\n\n/** The recorded snapshot body of a usage recording, parsed. */\nexport const recordedUsageBody = (recording: FixtureRecording): Schema.Json =>\n parseJson(recording.response.chunks.join('')) ?? null\n\nexport const makeSubscriptionUsageEmulator = (\n config: SubscriptionUsageEmulatorConfig\n): SubscriptionUsageEmulator =>\n makeFixtureRouteEmulator({\n method: 'GET',\n path: config.path,\n routes: config.routes,\n recordings: [config.recording],\n credential: 'bearer',\n headers: config.headers,\n replaceableBody: { defaultBody: config.subscriptionUsage },\n inputInvalid: config.inputInvalid\n })\n"],"mappings":";;;;AA2BA,MAAa,yBAAyB;;AAyBtC,MAAa,qBAAqB,cAChC,UAAU,UAAU,SAAS,OAAO,KAAK,EAAE,CAAC,KAAK;AAEnD,MAAa,iCACX,WAEA,yBAAyB;CACvB,QAAQ;CACR,MAAM,OAAO;CACb,QAAQ,OAAO;CACf,YAAY,CAAC,OAAO,SAAS;CAC7B,YAAY;CACZ,SAAS,OAAO;CAChB,iBAAiB,EAAE,aAAa,OAAO,kBAAkB;CACzD,cAAc,OAAO;AACvB,CAAC"}
@@ -0,0 +1,34 @@
1
+ import { StatefulResolution, StatefulRoute } from "../stateful-emulator.mjs";
2
+ import { TelegramEmulatorState } from "./state.mjs";
3
+
4
+ //#region src/telegram/api.d.ts
5
+ /** Drill knobs (tests only): each makes the emulator disagree with one conformance claim. */
6
+ type TelegramEmulatorDrills = {
7
+ /** `true`: `getChat` of a member chat answers 200 with `ok: false`. */readonly getChatOkFalse?: boolean; /** `true`: the `getChat` errors (absent chat, token naming no bot) answer 200, not 4xx. */
8
+ readonly errorsAs200?: boolean; /** `true`: `getFile` reports a `file_size` one byte larger than the file. */
9
+ readonly fileSizeOffByOne?: boolean; /** `true`: `sendMessage` answers 200 with `ok: false` (the message is still recorded as sent). */
10
+ readonly sendOkFalse?: boolean;
11
+ };
12
+ type TelegramApiEnv = {
13
+ /** Clock in epoch milliseconds (`date` of sent messages). */readonly now: () => number;
14
+ readonly drills: Required<TelegramEmulatorDrills>;
15
+ };
16
+ type TelegramApiRoute = {
17
+ readonly route: StatefulRoute<TelegramEmulatorState, TelegramApiEnv>;
18
+ readonly queryKeys: ReadonlyArray<string>; /** The token-free path the request must not repeat the token in (the method, or `/file`). */
19
+ readonly guardedPath: string;
20
+ };
21
+ /** The route table: evidence plus handler. `telegramEmulatorRoutes` is its evidence part. */
22
+ declare const telegramApiRoutes: ReadonlyArray<TelegramApiRoute>;
23
+ /**
24
+ * Resolve one Bot API request, failing closed. Only a request whose raw path is exactly an
25
+ * emulated route shape (`/bot<token>/<method>` or `/file/bot<token>/<file_path>`, the strict token
26
+ * on the raw segment, an emulated method, and no other path text) under that route's HTTP method
27
+ * is recognised; the token is extracted from that exact segment, never searched for elsewhere.
28
+ * Every other request is `unrecognised`: the wrapper ledgers and answers it with constant text
29
+ * only, so nothing it carries can leak.
30
+ */
31
+ declare const resolveTelegramRequest: (request: Request, url: URL) => StatefulResolution<TelegramEmulatorState, TelegramApiEnv>;
32
+ //#endregion
33
+ export { TelegramApiEnv, TelegramEmulatorDrills, resolveTelegramRequest, telegramApiRoutes };
34
+ //# sourceMappingURL=api.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.mts","names":[],"sources":["../../src/telegram/api.ts"],"mappings":";;;;;KAmCY,sBAAA;EAAA,gFAED,cAAA;WAEA,WAAA,YAFA;EAAA,SAIA,gBAAA;EAAA,SAEA,WAAA;AAAA;AAAA,KAGC,cAAA;EAAA,sEAED,GAAA;EAAA,SACA,MAAA,EAAQ,QAAQ,CAAC,sBAAA;AAAA;AAAA,KA2BvB,gBAAA;EAAA,SACM,KAAA,EAAO,aAAA,CAAc,qBAAA,EAAuB,cAAA;EAAA,SAC5C,SAAA,EAAW,aAAA,UA7BM;EAAA,SA+BjB,WAAA;AAAA;AA9BV;AAAA,cA8QY,iBAAA,EAAmB,aAAa,CAAC,gBAAA;;;;;;;;;cAuCjC,sBAAA,GACX,OAAA,EAAS,OAAA,EACT,GAAA,EAAK,GAAA,KACJ,kBAAA,CAAmB,qBAAA,EAAuB,cAAA"}