@aryee337/aery-ai 0.2.28 → 0.2.29

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 (417) hide show
  1. package/CHANGELOG.md +2914 -0
  2. package/README.md +614 -813
  3. package/package.json +140 -105
  4. package/src/api-registry.ts +96 -0
  5. package/src/auth-broker/client.ts +358 -0
  6. package/src/auth-broker/index.ts +5 -0
  7. package/src/auth-broker/refresher.ts +117 -0
  8. package/src/auth-broker/remote-store.ts +623 -0
  9. package/src/auth-broker/server.ts +644 -0
  10. package/src/auth-broker/types.ts +127 -0
  11. package/src/auth-broker/wire-schemas.ts +200 -0
  12. package/src/auth-gateway/http.ts +194 -0
  13. package/src/auth-gateway/index.ts +3 -0
  14. package/src/auth-gateway/server.ts +818 -0
  15. package/src/auth-gateway/types.ts +143 -0
  16. package/src/auth-storage.ts +4422 -0
  17. package/src/index.ts +54 -0
  18. package/src/model-cache.ts +129 -0
  19. package/src/model-manager.ts +469 -0
  20. package/src/model-thinking.ts +782 -0
  21. package/src/models.json +83530 -0
  22. package/src/models.json.d.ts +9 -0
  23. package/src/models.ts +56 -0
  24. package/src/prompts/turn-aborted-guidance.md +4 -0
  25. package/src/provider-details.ts +90 -0
  26. package/src/provider-models/bundled-references.ts +38 -0
  27. package/src/provider-models/descriptors.ts +355 -0
  28. package/src/provider-models/google.ts +88 -0
  29. package/src/provider-models/index.ts +5 -0
  30. package/src/provider-models/ollama.ts +153 -0
  31. package/src/provider-models/openai-compat.ts +2817 -0
  32. package/src/provider-models/special.ts +67 -0
  33. package/src/providers/aery-native-client.ts +228 -0
  34. package/src/providers/aery-native-server.ts +212 -0
  35. package/src/providers/amazon-bedrock.ts +873 -0
  36. package/src/providers/anthropic-client.ts +318 -0
  37. package/src/providers/anthropic-messages-server-schema.ts +243 -0
  38. package/src/providers/anthropic-messages-server.ts +683 -0
  39. package/src/providers/anthropic-wire.ts +268 -0
  40. package/src/providers/anthropic.ts +3094 -0
  41. package/src/providers/aws-credentials.ts +501 -0
  42. package/src/providers/aws-eventstream.ts +185 -0
  43. package/src/providers/aws-sigv4.ts +218 -0
  44. package/src/providers/azure-openai-responses.ts +361 -0
  45. package/src/providers/cursor/gen/agent_pb.ts +15274 -0
  46. package/src/providers/cursor/proto/agent.proto +3526 -0
  47. package/src/providers/cursor/proto/buf.gen.yaml +6 -0
  48. package/src/providers/cursor/proto/buf.yaml +17 -0
  49. package/src/providers/cursor.ts +2621 -0
  50. package/src/providers/error-message.ts +21 -0
  51. package/src/providers/github-copilot-headers.ts +140 -0
  52. package/src/providers/gitlab-duo.ts +372 -0
  53. package/src/providers/google-auth.ts +252 -0
  54. package/src/providers/google-gemini-cli.ts +809 -0
  55. package/src/providers/google-gemini-headers.ts +41 -0
  56. package/src/providers/google-shared.ts +917 -0
  57. package/src/providers/google-types.ts +167 -0
  58. package/src/providers/google-vertex.ts +91 -0
  59. package/src/providers/google.ts +41 -0
  60. package/src/providers/grammar.ts +70 -0
  61. package/src/providers/kimi.ts +52 -0
  62. package/src/providers/mock.ts +496 -0
  63. package/src/providers/ollama.ts +644 -0
  64. package/src/providers/openai-anthropic-shim.ts +138 -0
  65. package/src/providers/openai-chat-server-schema.ts +252 -0
  66. package/src/providers/openai-chat-server.ts +647 -0
  67. package/src/providers/openai-codex/constants.ts +43 -0
  68. package/src/providers/openai-codex/request-transformer.ts +161 -0
  69. package/src/providers/openai-codex/response-handler.ts +81 -0
  70. package/src/providers/openai-codex-responses.ts +3018 -0
  71. package/src/providers/openai-completions-compat.ts +300 -0
  72. package/src/providers/openai-completions.ts +1979 -0
  73. package/src/providers/openai-responses-server-schema.ts +290 -0
  74. package/src/providers/openai-responses-server.ts +1183 -0
  75. package/src/providers/openai-responses-shared.ts +873 -0
  76. package/src/providers/openai-responses.ts +679 -0
  77. package/src/providers/register-builtins.ts +436 -0
  78. package/src/providers/synthetic.ts +50 -0
  79. package/src/providers/transform-messages.ts +382 -0
  80. package/src/providers/vision-guard.ts +31 -0
  81. package/src/providers/xai-responses.ts +82 -0
  82. package/src/rate-limit-utils.ts +84 -0
  83. package/src/stream.ts +1065 -0
  84. package/src/types.ts +944 -0
  85. package/src/usage/claude.ts +482 -0
  86. package/src/usage/gemini.ts +250 -0
  87. package/src/usage/github-copilot.ts +421 -0
  88. package/src/usage/google-antigravity.ts +201 -0
  89. package/src/usage/kimi.ts +271 -0
  90. package/src/usage/minimax-code.ts +31 -0
  91. package/src/usage/openai-codex.ts +503 -0
  92. package/src/usage/shared.ts +10 -0
  93. package/src/usage/zai.ts +247 -0
  94. package/src/usage.ts +185 -0
  95. package/src/utils/abort.ts +51 -0
  96. package/src/utils/abortable-iterator.ts +69 -0
  97. package/src/utils/anthropic-auth.ts +93 -0
  98. package/src/utils/discovery/antigravity.ts +261 -0
  99. package/src/utils/discovery/codex.ts +371 -0
  100. package/src/utils/discovery/cursor.ts +306 -0
  101. package/src/utils/discovery/gemini.ts +248 -0
  102. package/src/utils/discovery/index.ts +4 -0
  103. package/src/utils/discovery/openai-compatible.ts +224 -0
  104. package/src/utils/event-stream.ts +142 -0
  105. package/src/utils/fireworks-model-id.ts +30 -0
  106. package/src/utils/foundry.ts +8 -0
  107. package/src/utils/http-inspector.ts +176 -0
  108. package/src/utils/idle-iterator.ts +267 -0
  109. package/src/utils/json-parse.ts +182 -0
  110. package/src/utils/oauth/__tests__/xai-oauth.test.ts +107 -0
  111. package/src/utils/oauth/alibaba-coding-plan.ts +59 -0
  112. package/src/utils/oauth/anthropic.ts +273 -0
  113. package/src/utils/oauth/api-key-login.ts +87 -0
  114. package/src/utils/oauth/api-key-validation.ts +92 -0
  115. package/src/utils/oauth/callback-server.ts +276 -0
  116. package/src/utils/oauth/cerebras.ts +16 -0
  117. package/src/utils/oauth/cloudflare-ai-gateway.ts +48 -0
  118. package/src/utils/oauth/cursor.ts +157 -0
  119. package/src/utils/oauth/deepseek.ts +53 -0
  120. package/src/utils/oauth/firepass.ts +24 -0
  121. package/src/utils/oauth/fireworks.ts +15 -0
  122. package/src/utils/oauth/github-copilot.ts +362 -0
  123. package/src/utils/oauth/gitlab-duo.ts +123 -0
  124. package/src/utils/oauth/google-antigravity.ts +200 -0
  125. package/src/utils/oauth/google-gemini-cli.ts +256 -0
  126. package/src/utils/oauth/google-oauth-shared.ts +110 -0
  127. package/src/utils/oauth/huggingface.ts +62 -0
  128. package/src/utils/oauth/index.ts +484 -0
  129. package/src/utils/oauth/kagi.ts +47 -0
  130. package/src/utils/oauth/kilo.ts +87 -0
  131. package/src/utils/oauth/kimi.ts +254 -0
  132. package/src/utils/oauth/litellm.ts +47 -0
  133. package/src/utils/oauth/lm-studio.ts +38 -0
  134. package/src/utils/oauth/minimax-code.ts +78 -0
  135. package/src/utils/oauth/moonshot.ts +23 -0
  136. package/src/utils/oauth/nanogpt.ts +15 -0
  137. package/src/utils/oauth/nvidia.ts +70 -0
  138. package/src/utils/oauth/oauth.html +203 -0
  139. package/src/utils/oauth/ollama-cloud.ts +28 -0
  140. package/src/utils/oauth/ollama.ts +47 -0
  141. package/src/utils/oauth/openai-codex.ts +299 -0
  142. package/src/utils/oauth/opencode.ts +49 -0
  143. package/src/utils/oauth/openrouter.ts +20 -0
  144. package/src/utils/oauth/parallel.ts +46 -0
  145. package/src/utils/oauth/perplexity.ts +206 -0
  146. package/src/utils/oauth/pkce.ts +18 -0
  147. package/src/utils/oauth/qianfan.ts +58 -0
  148. package/src/utils/oauth/qwen-portal.ts +60 -0
  149. package/src/utils/oauth/synthetic.ts +15 -0
  150. package/src/utils/oauth/tavily.ts +46 -0
  151. package/src/utils/oauth/together.ts +16 -0
  152. package/src/utils/oauth/types.ts +99 -0
  153. package/src/utils/oauth/venice.ts +59 -0
  154. package/src/utils/oauth/vercel-ai-gateway.ts +47 -0
  155. package/src/utils/oauth/vllm.ts +40 -0
  156. package/src/utils/oauth/wafer.ts +50 -0
  157. package/src/utils/oauth/xai-oauth.ts +342 -0
  158. package/src/utils/oauth/xiaomi.ts +139 -0
  159. package/src/utils/oauth/zai.ts +60 -0
  160. package/src/utils/oauth/zenmux.ts +15 -0
  161. package/src/utils/oauth/zhipu.ts +60 -0
  162. package/src/utils/overflow.ts +137 -0
  163. package/src/utils/parse-bind.ts +54 -0
  164. package/src/utils/provider-response.ts +30 -0
  165. package/src/utils/request-debug.ts +336 -0
  166. package/src/utils/retry-after.ts +110 -0
  167. package/src/utils/retry.ts +54 -0
  168. package/src/utils/schema/CONSTRAINTS.md +164 -0
  169. package/src/utils/schema/adapt.ts +36 -0
  170. package/src/utils/schema/compatibility.ts +435 -0
  171. package/src/utils/schema/dereference.ts +98 -0
  172. package/src/utils/schema/draft.ts +341 -0
  173. package/src/utils/schema/equality.ts +97 -0
  174. package/src/utils/schema/fields.ts +191 -0
  175. package/src/utils/schema/index.ts +13 -0
  176. package/src/utils/schema/json-schema-validator.ts +577 -0
  177. package/src/utils/schema/meta-validator.ts +167 -0
  178. package/src/utils/schema/normalize.ts +1588 -0
  179. package/src/utils/schema/spill.ts +43 -0
  180. package/src/utils/schema/stamps.ts +97 -0
  181. package/src/utils/schema/types.ts +10 -0
  182. package/src/utils/schema/wire.ts +293 -0
  183. package/src/utils/schema/zod-decontaminate.ts +331 -0
  184. package/src/utils/sdk-stream-timeout.ts +43 -0
  185. package/src/utils/sse-debug.ts +289 -0
  186. package/src/utils/stream-markup-healing.ts +612 -0
  187. package/src/utils/tool-choice.ts +99 -0
  188. package/src/utils/validation.ts +1024 -0
  189. package/src/utils.ts +166 -0
  190. package/dist/api-registry.d.ts +0 -20
  191. package/dist/api-registry.d.ts.map +0 -1
  192. package/dist/api-registry.js +0 -44
  193. package/dist/api-registry.js.map +0 -1
  194. package/dist/bedrock-provider.d.ts +0 -5
  195. package/dist/bedrock-provider.d.ts.map +0 -1
  196. package/dist/bedrock-provider.js +0 -6
  197. package/dist/bedrock-provider.js.map +0 -1
  198. package/dist/cli.d.ts +0 -3
  199. package/dist/cli.d.ts.map +0 -1
  200. package/dist/cli.js +0 -130
  201. package/dist/cli.js.map +0 -1
  202. package/dist/env-api-keys.d.ts +0 -18
  203. package/dist/env-api-keys.d.ts.map +0 -1
  204. package/dist/env-api-keys.js +0 -178
  205. package/dist/env-api-keys.js.map +0 -1
  206. package/dist/image-models.d.ts +0 -10
  207. package/dist/image-models.d.ts.map +0 -1
  208. package/dist/image-models.generated.d.ts +0 -440
  209. package/dist/image-models.generated.d.ts.map +0 -1
  210. package/dist/image-models.generated.js +0 -442
  211. package/dist/image-models.generated.js.map +0 -1
  212. package/dist/image-models.js +0 -23
  213. package/dist/image-models.js.map +0 -1
  214. package/dist/images-api-registry.d.ts +0 -14
  215. package/dist/images-api-registry.d.ts.map +0 -1
  216. package/dist/images-api-registry.js +0 -22
  217. package/dist/images-api-registry.js.map +0 -1
  218. package/dist/images.d.ts +0 -4
  219. package/dist/images.d.ts.map +0 -1
  220. package/dist/images.js +0 -14
  221. package/dist/images.js.map +0 -1
  222. package/dist/index.d.ts +0 -32
  223. package/dist/index.d.ts.map +0 -1
  224. package/dist/index.js +0 -20
  225. package/dist/index.js.map +0 -1
  226. package/dist/models.d.ts +0 -18
  227. package/dist/models.d.ts.map +0 -1
  228. package/dist/models.generated.d.ts +0 -17707
  229. package/dist/models.generated.d.ts.map +0 -1
  230. package/dist/models.generated.js +0 -16561
  231. package/dist/models.generated.js.map +0 -1
  232. package/dist/models.js +0 -71
  233. package/dist/models.js.map +0 -1
  234. package/dist/oauth.d.ts +0 -2
  235. package/dist/oauth.d.ts.map +0 -1
  236. package/dist/oauth.js +0 -2
  237. package/dist/oauth.js.map +0 -1
  238. package/dist/providers/aery-error-formatting.d.ts +0 -13
  239. package/dist/providers/aery-error-formatting.d.ts.map +0 -1
  240. package/dist/providers/aery-error-formatting.js +0 -112
  241. package/dist/providers/aery-error-formatting.js.map +0 -1
  242. package/dist/providers/amazon-bedrock.d.ts +0 -38
  243. package/dist/providers/amazon-bedrock.d.ts.map +0 -1
  244. package/dist/providers/amazon-bedrock.js +0 -763
  245. package/dist/providers/amazon-bedrock.js.map +0 -1
  246. package/dist/providers/anthropic.d.ts +0 -71
  247. package/dist/providers/anthropic.d.ts.map +0 -1
  248. package/dist/providers/anthropic.js +0 -949
  249. package/dist/providers/anthropic.js.map +0 -1
  250. package/dist/providers/azure-openai-responses.d.ts +0 -15
  251. package/dist/providers/azure-openai-responses.d.ts.map +0 -1
  252. package/dist/providers/azure-openai-responses.js +0 -225
  253. package/dist/providers/azure-openai-responses.js.map +0 -1
  254. package/dist/providers/cloudflare.d.ts +0 -13
  255. package/dist/providers/cloudflare.d.ts.map +0 -1
  256. package/dist/providers/cloudflare.js +0 -26
  257. package/dist/providers/cloudflare.js.map +0 -1
  258. package/dist/providers/faux.d.ts +0 -56
  259. package/dist/providers/faux.d.ts.map +0 -1
  260. package/dist/providers/faux.js +0 -368
  261. package/dist/providers/faux.js.map +0 -1
  262. package/dist/providers/github-copilot-headers.d.ts +0 -8
  263. package/dist/providers/github-copilot-headers.d.ts.map +0 -1
  264. package/dist/providers/github-copilot-headers.js +0 -29
  265. package/dist/providers/github-copilot-headers.js.map +0 -1
  266. package/dist/providers/google-gemini-cli.d.ts +0 -74
  267. package/dist/providers/google-gemini-cli.d.ts.map +0 -1
  268. package/dist/providers/google-gemini-cli.js +0 -779
  269. package/dist/providers/google-gemini-cli.js.map +0 -1
  270. package/dist/providers/google-shared.d.ts +0 -70
  271. package/dist/providers/google-shared.d.ts.map +0 -1
  272. package/dist/providers/google-shared.js +0 -329
  273. package/dist/providers/google-shared.js.map +0 -1
  274. package/dist/providers/google-vertex.d.ts +0 -15
  275. package/dist/providers/google-vertex.d.ts.map +0 -1
  276. package/dist/providers/google-vertex.js +0 -442
  277. package/dist/providers/google-vertex.js.map +0 -1
  278. package/dist/providers/google.d.ts +0 -13
  279. package/dist/providers/google.d.ts.map +0 -1
  280. package/dist/providers/google.js +0 -400
  281. package/dist/providers/google.js.map +0 -1
  282. package/dist/providers/images/openrouter.d.ts +0 -3
  283. package/dist/providers/images/openrouter.d.ts.map +0 -1
  284. package/dist/providers/images/openrouter.js +0 -129
  285. package/dist/providers/images/openrouter.js.map +0 -1
  286. package/dist/providers/images/register-builtins.d.ts +0 -4
  287. package/dist/providers/images/register-builtins.d.ts.map +0 -1
  288. package/dist/providers/images/register-builtins.js +0 -34
  289. package/dist/providers/images/register-builtins.js.map +0 -1
  290. package/dist/providers/mistral.d.ts +0 -25
  291. package/dist/providers/mistral.d.ts.map +0 -1
  292. package/dist/providers/mistral.js +0 -535
  293. package/dist/providers/mistral.js.map +0 -1
  294. package/dist/providers/openai-codex-responses.d.ts +0 -30
  295. package/dist/providers/openai-codex-responses.d.ts.map +0 -1
  296. package/dist/providers/openai-codex-responses.js +0 -1090
  297. package/dist/providers/openai-codex-responses.js.map +0 -1
  298. package/dist/providers/openai-completions.d.ts +0 -19
  299. package/dist/providers/openai-completions.d.ts.map +0 -1
  300. package/dist/providers/openai-completions.js +0 -950
  301. package/dist/providers/openai-completions.js.map +0 -1
  302. package/dist/providers/openai-prompt-cache.d.ts +0 -3
  303. package/dist/providers/openai-prompt-cache.d.ts.map +0 -1
  304. package/dist/providers/openai-prompt-cache.js +0 -10
  305. package/dist/providers/openai-prompt-cache.js.map +0 -1
  306. package/dist/providers/openai-responses-shared.d.ts +0 -18
  307. package/dist/providers/openai-responses-shared.d.ts.map +0 -1
  308. package/dist/providers/openai-responses-shared.js +0 -492
  309. package/dist/providers/openai-responses-shared.js.map +0 -1
  310. package/dist/providers/openai-responses.d.ts +0 -13
  311. package/dist/providers/openai-responses.d.ts.map +0 -1
  312. package/dist/providers/openai-responses.js +0 -237
  313. package/dist/providers/openai-responses.js.map +0 -1
  314. package/dist/providers/register-builtins.d.ts +0 -38
  315. package/dist/providers/register-builtins.d.ts.map +0 -1
  316. package/dist/providers/register-builtins.js +0 -278
  317. package/dist/providers/register-builtins.js.map +0 -1
  318. package/dist/providers/simple-options.d.ts +0 -8
  319. package/dist/providers/simple-options.d.ts.map +0 -1
  320. package/dist/providers/simple-options.js +0 -41
  321. package/dist/providers/simple-options.js.map +0 -1
  322. package/dist/providers/transform-messages.d.ts +0 -8
  323. package/dist/providers/transform-messages.d.ts.map +0 -1
  324. package/dist/providers/transform-messages.js +0 -184
  325. package/dist/providers/transform-messages.js.map +0 -1
  326. package/dist/session-resources.d.ts +0 -4
  327. package/dist/session-resources.d.ts.map +0 -1
  328. package/dist/session-resources.js +0 -22
  329. package/dist/session-resources.js.map +0 -1
  330. package/dist/stream.d.ts +0 -8
  331. package/dist/stream.d.ts.map +0 -1
  332. package/dist/stream.js +0 -27
  333. package/dist/stream.js.map +0 -1
  334. package/dist/types.d.ts +0 -498
  335. package/dist/types.d.ts.map +0 -1
  336. package/dist/types.js +0 -2
  337. package/dist/types.js.map +0 -1
  338. package/dist/utils/diagnostics.d.ts +0 -19
  339. package/dist/utils/diagnostics.d.ts.map +0 -1
  340. package/dist/utils/diagnostics.js +0 -25
  341. package/dist/utils/diagnostics.js.map +0 -1
  342. package/dist/utils/event-stream.d.ts +0 -21
  343. package/dist/utils/event-stream.d.ts.map +0 -1
  344. package/dist/utils/event-stream.js +0 -81
  345. package/dist/utils/event-stream.js.map +0 -1
  346. package/dist/utils/hash.d.ts +0 -3
  347. package/dist/utils/hash.d.ts.map +0 -1
  348. package/dist/utils/hash.js +0 -14
  349. package/dist/utils/hash.js.map +0 -1
  350. package/dist/utils/headers.d.ts +0 -2
  351. package/dist/utils/headers.d.ts.map +0 -1
  352. package/dist/utils/headers.js +0 -8
  353. package/dist/utils/headers.js.map +0 -1
  354. package/dist/utils/json-parse.d.ts +0 -16
  355. package/dist/utils/json-parse.d.ts.map +0 -1
  356. package/dist/utils/json-parse.js +0 -113
  357. package/dist/utils/json-parse.js.map +0 -1
  358. package/dist/utils/node-http-proxy.d.ts +0 -10
  359. package/dist/utils/node-http-proxy.d.ts.map +0 -1
  360. package/dist/utils/node-http-proxy.js +0 -97
  361. package/dist/utils/node-http-proxy.js.map +0 -1
  362. package/dist/utils/oauth/anthropic.d.ts +0 -25
  363. package/dist/utils/oauth/anthropic.d.ts.map +0 -1
  364. package/dist/utils/oauth/anthropic.js +0 -335
  365. package/dist/utils/oauth/anthropic.js.map +0 -1
  366. package/dist/utils/oauth/device-code.d.ts +0 -19
  367. package/dist/utils/oauth/device-code.d.ts.map +0 -1
  368. package/dist/utils/oauth/device-code.js +0 -55
  369. package/dist/utils/oauth/device-code.js.map +0 -1
  370. package/dist/utils/oauth/github-copilot.d.ts +0 -30
  371. package/dist/utils/oauth/github-copilot.d.ts.map +0 -1
  372. package/dist/utils/oauth/github-copilot.js +0 -268
  373. package/dist/utils/oauth/github-copilot.js.map +0 -1
  374. package/dist/utils/oauth/google-antigravity.d.ts +0 -26
  375. package/dist/utils/oauth/google-antigravity.d.ts.map +0 -1
  376. package/dist/utils/oauth/google-antigravity.js +0 -377
  377. package/dist/utils/oauth/google-antigravity.js.map +0 -1
  378. package/dist/utils/oauth/google-gemini-cli.d.ts +0 -26
  379. package/dist/utils/oauth/google-gemini-cli.d.ts.map +0 -1
  380. package/dist/utils/oauth/google-gemini-cli.js +0 -482
  381. package/dist/utils/oauth/google-gemini-cli.js.map +0 -1
  382. package/dist/utils/oauth/index.d.ts +0 -63
  383. package/dist/utils/oauth/index.d.ts.map +0 -1
  384. package/dist/utils/oauth/index.js +0 -131
  385. package/dist/utils/oauth/index.js.map +0 -1
  386. package/dist/utils/oauth/oauth-page.d.ts +0 -3
  387. package/dist/utils/oauth/oauth-page.d.ts.map +0 -1
  388. package/dist/utils/oauth/oauth-page.js +0 -105
  389. package/dist/utils/oauth/oauth-page.js.map +0 -1
  390. package/dist/utils/oauth/openai-codex.d.ts +0 -34
  391. package/dist/utils/oauth/openai-codex.d.ts.map +0 -1
  392. package/dist/utils/oauth/openai-codex.js +0 -385
  393. package/dist/utils/oauth/openai-codex.js.map +0 -1
  394. package/dist/utils/oauth/pkce.d.ts +0 -13
  395. package/dist/utils/oauth/pkce.d.ts.map +0 -1
  396. package/dist/utils/oauth/pkce.js +0 -31
  397. package/dist/utils/oauth/pkce.js.map +0 -1
  398. package/dist/utils/oauth/types.d.ts +0 -64
  399. package/dist/utils/oauth/types.d.ts.map +0 -1
  400. package/dist/utils/oauth/types.js +0 -2
  401. package/dist/utils/oauth/types.js.map +0 -1
  402. package/dist/utils/overflow.d.ts +0 -56
  403. package/dist/utils/overflow.d.ts.map +0 -1
  404. package/dist/utils/overflow.js +0 -151
  405. package/dist/utils/overflow.js.map +0 -1
  406. package/dist/utils/sanitize-unicode.d.ts +0 -22
  407. package/dist/utils/sanitize-unicode.d.ts.map +0 -1
  408. package/dist/utils/sanitize-unicode.js +0 -26
  409. package/dist/utils/sanitize-unicode.js.map +0 -1
  410. package/dist/utils/typebox-helpers.d.ts +0 -17
  411. package/dist/utils/typebox-helpers.d.ts.map +0 -1
  412. package/dist/utils/typebox-helpers.js +0 -21
  413. package/dist/utils/typebox-helpers.js.map +0 -1
  414. package/dist/utils/validation.d.ts +0 -18
  415. package/dist/utils/validation.d.ts.map +0 -1
  416. package/dist/utils/validation.js +0 -281
  417. package/dist/utils/validation.js.map +0 -1
@@ -0,0 +1,358 @@
1
+ /**
2
+ * HTTP client for the aery auth-broker server.
3
+ *
4
+ * Used by {@link RemoteAuthCredentialStore} (snapshot pulls) and by
5
+ * `aery auth-broker status` (liveness checks). All endpoints except
6
+ * `/v1/healthz` require a bearer token.
7
+ */
8
+ import { readSseEvents } from "@aryee337/aery-utils";
9
+ import type { ZodType, infer as zInfer } from "zod/v4";
10
+ import type { AuthCredential } from "../auth-storage";
11
+ import type {
12
+ CredentialDisableRequest,
13
+ CredentialDisableResponse,
14
+ CredentialRefreshResponse,
15
+ CredentialUploadRequest,
16
+ CredentialUploadResponse,
17
+ HealthzResponse,
18
+ SnapshotResponse,
19
+ SnapshotStreamEvent,
20
+ UsageResponse,
21
+ } from "./types";
22
+ import {
23
+ credentialDisableResponseSchema,
24
+ credentialRefreshResponseSchema,
25
+ credentialUploadResponseSchema,
26
+ healthzResponseSchema,
27
+ snapshotResponseSchema,
28
+ snapshotStreamEventSchema,
29
+ usageResponseSchema,
30
+ } from "./wire-schemas";
31
+
32
+ export interface AuthBrokerClientOptions {
33
+ /** Base URL (e.g. `https://broker.tailnet:8765`). Trailing slashes are trimmed. */
34
+ url: string;
35
+ /** Bearer token used for everything except `healthz`. */
36
+ token: string;
37
+ /** Per-request timeout in milliseconds. Default 10s. */
38
+ timeoutMs?: number;
39
+ /** Retry connection errors this many times. Default 1. */
40
+ maxRetries?: number;
41
+ /** Override fetch (used in tests). Default global `fetch`. */
42
+ fetchImpl?: typeof fetch;
43
+ }
44
+
45
+ export class AuthBrokerError extends Error {
46
+ readonly status: number | undefined;
47
+ readonly body: string | undefined;
48
+ constructor(message: string, opts: { status?: number; body?: string; cause?: unknown } = {}) {
49
+ super(message, { cause: opts.cause });
50
+ this.name = "AuthBrokerError";
51
+ this.status = opts.status;
52
+ this.body = opts.body;
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Thrown when a broker responds 404 to `GET /v1/snapshot/stream` — old
58
+ * brokers that predate the SSE endpoint. Callers (`RemoteAuthCredentialStore`)
59
+ * detect this sentinel to fall back to long-polling permanently.
60
+ */
61
+ export class AuthBrokerStreamUnsupportedError extends AuthBrokerError {
62
+ constructor(message = "Auth broker does not support /v1/snapshot/stream") {
63
+ super(message, { status: 404 });
64
+ this.name = "AuthBrokerStreamUnsupportedError";
65
+ }
66
+ }
67
+
68
+ export interface FetchSnapshotOptions {
69
+ ifGenerationGt?: number;
70
+ waitMs?: number;
71
+ signal?: AbortSignal;
72
+ }
73
+
74
+ export type FetchSnapshotResult =
75
+ | { status: 200; snapshot: SnapshotResponse; generation: number }
76
+ | { status: 304; generation: number };
77
+
78
+ function parseGenerationTag(header: string | null): number | undefined {
79
+ if (!header) return undefined;
80
+ let value = header.trim();
81
+ if (value.startsWith("W/")) value = value.slice(2).trim();
82
+ if (value.startsWith('"') && value.endsWith('"') && value.length >= 2) {
83
+ value = value.slice(1, -1);
84
+ }
85
+ const generation = Number(value);
86
+ if (!Number.isInteger(generation) || generation < 0) return undefined;
87
+ return generation;
88
+ }
89
+
90
+ const DEFAULT_TIMEOUT_MS = 10_000;
91
+ const DEFAULT_MAX_RETRIES = 1;
92
+
93
+ export class AuthBrokerClient {
94
+ readonly #baseUrl: string;
95
+ readonly #token: string;
96
+ readonly #timeoutMs: number;
97
+ readonly #maxRetries: number;
98
+ readonly #fetch: typeof fetch;
99
+
100
+ constructor(opts: AuthBrokerClientOptions) {
101
+ this.#baseUrl = opts.url.replace(/\/+$/, "");
102
+ this.#token = opts.token;
103
+ this.#timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
104
+ this.#maxRetries = opts.maxRetries ?? DEFAULT_MAX_RETRIES;
105
+ this.#fetch = opts.fetchImpl ?? fetch;
106
+ }
107
+
108
+ healthz(signal?: AbortSignal): Promise<HealthzResponse> {
109
+ return this.#request("GET", "/v1/healthz", { schema: healthzResponseSchema, auth: false, signal });
110
+ }
111
+
112
+ async fetchSnapshot(opts: FetchSnapshotOptions = {}): Promise<FetchSnapshotResult> {
113
+ return this.#fetchSnapshotResult(opts);
114
+ }
115
+ async #fetchSnapshotResult(opts: FetchSnapshotOptions): Promise<FetchSnapshotResult> {
116
+ const query = new URLSearchParams();
117
+ if (opts.waitMs !== undefined) query.set("wait", String(opts.waitMs));
118
+ const path = `/v1/snapshot${query.size > 0 ? `?${query.toString()}` : ""}`;
119
+ const headers: Record<string, string> = {};
120
+ if (opts.ifGenerationGt !== undefined) headers["If-None-Match"] = `"${opts.ifGenerationGt}"`;
121
+ const timeoutMs =
122
+ opts.waitMs !== undefined && opts.waitMs > 0 ? Math.max(this.#timeoutMs, opts.waitMs + 1000) : undefined;
123
+ const response = await this.#fetchRaw("GET", path, {
124
+ auth: true,
125
+ headers,
126
+ signal: opts.signal,
127
+ timeoutMs,
128
+ });
129
+ const etagGeneration = parseGenerationTag(response.headers.get("etag"));
130
+ if (response.status === 304) {
131
+ return { status: 304, generation: etagGeneration ?? opts.ifGenerationGt ?? 0 };
132
+ }
133
+ const text = await response.text();
134
+ const raw = this.#parseJson(text, response.status);
135
+ const validated = snapshotResponseSchema.safeParse(raw);
136
+ if (!validated.success) {
137
+ throw new AuthBrokerError("Auth broker response failed schema validation", {
138
+ status: response.status,
139
+ body: validated.error.message,
140
+ });
141
+ }
142
+ const snapshot = validated.data as SnapshotResponse;
143
+ return { status: 200, snapshot, generation: etagGeneration ?? snapshot.generation };
144
+ }
145
+
146
+ /**
147
+ * Subscribe to the broker's SSE snapshot stream. The first frame is always
148
+ * a full `snapshot`; subsequent frames are `entry` upserts / refreshes or
149
+ * `removed` deletes. Caller controls lifecycle via `opts.signal`.
150
+ *
151
+ * Throws {@link AuthBrokerStreamUnsupportedError} when the broker responds
152
+ * 404 — older brokers predate this endpoint and the caller should fall back
153
+ * to long-polling for the remainder of its lifetime.
154
+ */
155
+ async *openSnapshotStream(opts: { signal?: AbortSignal } = {}): AsyncGenerator<SnapshotStreamEvent> {
156
+ const url = `${this.#baseUrl}/v1/snapshot/stream`;
157
+ const headers: Record<string, string> = {
158
+ Accept: "text/event-stream",
159
+ Authorization: `Bearer ${this.#token}`,
160
+ };
161
+ if (opts.signal?.aborted) {
162
+ throw new AuthBrokerError("Auth broker request aborted", { cause: opts.signal.reason });
163
+ }
164
+ // No timeout: this connection is intentionally long-lived. Caller's signal
165
+ // is the only cancel path.
166
+ const response = await this.#fetch(url, { method: "GET", headers, signal: opts.signal });
167
+ if (response.status === 404) {
168
+ // Drain the body so the socket can be reused; tiny payload.
169
+ await response.text().catch(() => {});
170
+ throw new AuthBrokerStreamUnsupportedError();
171
+ }
172
+ if (!response.ok) {
173
+ const text = await response.text().catch(() => "");
174
+ throw new AuthBrokerError(`Auth broker stream failed: ${response.status} ${response.statusText}`, {
175
+ status: response.status,
176
+ body: text,
177
+ });
178
+ }
179
+ if (!response.body) {
180
+ throw new AuthBrokerError("Auth broker stream response had no body", { status: response.status });
181
+ }
182
+ const contentType = response.headers.get("content-type")?.toLowerCase();
183
+ if (contentType?.split(";", 1)[0].trim() !== "text/event-stream") {
184
+ await response.body.cancel().catch(() => {});
185
+ throw new AuthBrokerError("Auth broker stream returned non-SSE response", {
186
+ status: response.status,
187
+ body: contentType ?? "",
188
+ });
189
+ }
190
+
191
+ let sawFirstEvent = false;
192
+ for await (const sse of readSseEvents(response.body, opts.signal)) {
193
+ if (sse.event === null && sse.data === "") continue; // keepalive comment frames
194
+ let parsed: unknown;
195
+ try {
196
+ parsed = JSON.parse(sse.data);
197
+ } catch (err) {
198
+ throw new AuthBrokerError("Auth broker stream returned malformed JSON", {
199
+ body: sse.data,
200
+ cause: err,
201
+ });
202
+ }
203
+ const validated = snapshotStreamEventSchema.safeParse(parsed);
204
+ if (!validated.success) {
205
+ throw new AuthBrokerError("Auth broker stream event failed schema validation", {
206
+ body: validated.error.message,
207
+ });
208
+ }
209
+ const event = validated.data;
210
+ if (!sawFirstEvent) {
211
+ sawFirstEvent = true;
212
+ if (event.kind !== "snapshot") {
213
+ throw new AuthBrokerError("Auth broker stream did not start with snapshot", { body: sse.data });
214
+ }
215
+ }
216
+ yield event;
217
+ }
218
+ if (!opts.signal?.aborted) {
219
+ throw new AuthBrokerError(
220
+ sawFirstEvent
221
+ ? "Auth broker stream ended unexpectedly"
222
+ : "Auth broker stream ended before initial snapshot",
223
+ { status: response.status },
224
+ );
225
+ }
226
+ }
227
+
228
+ fetchUsage(signal?: AbortSignal): Promise<UsageResponse> {
229
+ // Validates the envelope (`generatedAt`, `reports[].provider`, `limits`,
230
+ // `metadata`) but leaves provider-specific extension fields permissive so
231
+ // the broker can ship new shapes ahead of the client. `raw` is accepted
232
+ // but normally stripped by the broker before send.
233
+ return this.#request("GET", "/v1/usage", { schema: usageResponseSchema, signal }) as Promise<UsageResponse>;
234
+ }
235
+
236
+ async refreshCredential(id: number, signal?: AbortSignal): Promise<CredentialRefreshResponse> {
237
+ return this.#request("POST", `/v1/credential/${id}/refresh`, {
238
+ schema: credentialRefreshResponseSchema,
239
+ signal,
240
+ }) as Promise<CredentialRefreshResponse>;
241
+ }
242
+
243
+ async disableCredential(id: number, cause: string, signal?: AbortSignal): Promise<CredentialDisableResponse> {
244
+ const body: CredentialDisableRequest = { cause };
245
+ return this.#request("POST", `/v1/credential/${id}/disable`, {
246
+ body,
247
+ schema: credentialDisableResponseSchema,
248
+ signal,
249
+ });
250
+ }
251
+
252
+ async uploadCredential(
253
+ provider: string,
254
+ credential: AuthCredential,
255
+ signal?: AbortSignal,
256
+ ): Promise<CredentialUploadResponse> {
257
+ const body: CredentialUploadRequest = { provider, credential };
258
+ return this.#request("POST", "/v1/credential", {
259
+ body,
260
+ schema: credentialUploadResponseSchema,
261
+ signal,
262
+ }) as Promise<CredentialUploadResponse>;
263
+ }
264
+
265
+ async #request<TSchema extends ZodType>(
266
+ method: "GET" | "POST",
267
+ path: string,
268
+ opts: { schema: TSchema; auth?: boolean; body?: unknown; signal?: AbortSignal },
269
+ ): Promise<zInfer<TSchema>> {
270
+ const response = await this.#fetchRaw(method, path, opts);
271
+ const text = await response.text();
272
+ const raw = this.#parseJson(text, response.status);
273
+ const validated = opts.schema.safeParse(raw);
274
+ if (!validated.success) {
275
+ throw new AuthBrokerError("Auth broker response failed schema validation", {
276
+ status: response.status,
277
+ body: validated.error.message,
278
+ });
279
+ }
280
+ return validated.data;
281
+ }
282
+
283
+ #parseJson(text: string, status: number): unknown {
284
+ try {
285
+ return text.length === 0 ? null : JSON.parse(text);
286
+ } catch (parseError) {
287
+ throw new AuthBrokerError("Auth broker returned malformed JSON", {
288
+ status,
289
+ body: text,
290
+ cause: parseError,
291
+ });
292
+ }
293
+ }
294
+
295
+ async #fetchRaw(
296
+ method: "GET" | "POST",
297
+ path: string,
298
+ opts: {
299
+ auth?: boolean;
300
+ body?: unknown;
301
+ signal?: AbortSignal;
302
+ headers?: Record<string, string>;
303
+ timeoutMs?: number;
304
+ },
305
+ ): Promise<Response> {
306
+ const auth = opts.auth ?? true;
307
+ const url = `${this.#baseUrl}${path}`;
308
+ const headers: Record<string, string> = { Accept: "application/json", ...(opts.headers ?? {}) };
309
+ if (auth) headers.Authorization = `Bearer ${this.#token}`;
310
+ let payload: string | undefined;
311
+ if (opts.body !== undefined) {
312
+ payload = JSON.stringify(opts.body);
313
+ headers["Content-Type"] = "application/json";
314
+ }
315
+
316
+ // Fast-fail when the caller's signal is already aborted — avoids spinning
317
+ // up a fetch + timer that the first `await` would just abort anyway.
318
+ if (opts.signal?.aborted) {
319
+ throw new AuthBrokerError("Auth broker request aborted", { cause: opts.signal.reason });
320
+ }
321
+
322
+ let lastError: unknown;
323
+ for (let attempt = 0; attempt <= this.#maxRetries; attempt += 1) {
324
+ const timeoutSignal = AbortSignal.timeout(opts.timeoutMs ?? this.#timeoutMs);
325
+ const signal = opts.signal ? AbortSignal.any([opts.signal, timeoutSignal]) : timeoutSignal;
326
+ try {
327
+ const response = await this.#fetch(url, {
328
+ method,
329
+ headers,
330
+ body: payload,
331
+ signal,
332
+ });
333
+ if (!response.ok && response.status !== 304) {
334
+ const text = await response.text();
335
+ throw new AuthBrokerError(`Auth broker request failed: ${response.status} ${response.statusText}`, {
336
+ status: response.status,
337
+ body: text,
338
+ });
339
+ }
340
+ return response;
341
+ } catch (error) {
342
+ lastError = error;
343
+ // Caller-driven abort wins over retry — the caller said stop.
344
+ if (opts.signal?.aborted) {
345
+ throw new AuthBrokerError("Auth broker request aborted", { cause: opts.signal.reason });
346
+ }
347
+ if (error instanceof AuthBrokerError && error.status !== undefined) {
348
+ // HTTP errors (4xx/5xx) don't retry — caller knows what to do.
349
+ throw error;
350
+ }
351
+ if (attempt >= this.#maxRetries) break;
352
+ }
353
+ }
354
+ throw new AuthBrokerError(`Auth broker request failed after ${this.#maxRetries + 1} attempt(s)`, {
355
+ cause: lastError,
356
+ });
357
+ }
358
+ }
@@ -0,0 +1,5 @@
1
+ export * from "./client";
2
+ export * from "./refresher";
3
+ export * from "./remote-store";
4
+ export * from "./server";
5
+ export * from "./types";
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Background OAuth refresh loop for the auth-broker server.
3
+ *
4
+ * Iterates active OAuth credentials at `refreshIntervalMs` cadence, refreshing
5
+ * any whose `expires - Date.now() < refreshSkewMs`. Refresh single-flight
6
+ * lives in {@link AuthStorage} so manual and background refreshes share the
7
+ * same upstream attempt.
8
+ * Definitively-failed credentials (invalid_grant / 401 not from network blip)
9
+ * are disabled via {@link AuthStorage.disableCredentialById} so the next
10
+ * snapshot pull surfaces a clean delete on the client.
11
+ */
12
+ import { logger } from "@aryee337/aery-utils";
13
+ import { type AuthStorage, isDefinitiveOAuthFailure } from "../auth-storage";
14
+ import { DEFAULT_REFRESH_INTERVAL_MS, DEFAULT_REFRESH_SKEW_MS } from "./types";
15
+
16
+ export interface AuthBrokerRefresherOptions {
17
+ storage: AuthStorage;
18
+ /** Refresh credentials expiring within this window. Default 5 min. */
19
+ refreshSkewMs?: number;
20
+ /** Loop cadence. Default 60s. */
21
+ refreshIntervalMs?: number;
22
+ /** Override clock (tests). */
23
+ now?: () => number;
24
+ }
25
+
26
+ export interface AuthBrokerRefresherSchedule {
27
+ enabled: boolean;
28
+ intervalMs: number;
29
+ skewMs: number;
30
+ nextSweepAt: number;
31
+ }
32
+
33
+ export class AuthBrokerRefresher {
34
+ readonly #storage: AuthStorage;
35
+ readonly #refreshSkewMs: number;
36
+ readonly #refreshIntervalMs: number;
37
+ readonly #now: () => number;
38
+ #timer: NodeJS.Timeout | undefined;
39
+ #running = false;
40
+ #nextSweepAt: number;
41
+ constructor(opts: AuthBrokerRefresherOptions) {
42
+ this.#storage = opts.storage;
43
+ this.#refreshSkewMs = opts.refreshSkewMs ?? DEFAULT_REFRESH_SKEW_MS;
44
+ this.#refreshIntervalMs = opts.refreshIntervalMs ?? DEFAULT_REFRESH_INTERVAL_MS;
45
+ this.#now = opts.now ?? Date.now;
46
+ this.#nextSweepAt = this.#now();
47
+ }
48
+
49
+ start(): void {
50
+ if (this.#timer !== undefined) return;
51
+ // Refresh sweep is best-effort; kick once immediately so freshly-booted
52
+ // brokers don't hand out near-expired tokens for the first interval.
53
+ this.#nextSweepAt = this.#now();
54
+ void this.tick();
55
+ this.#timer = setInterval(() => {
56
+ void this.tick();
57
+ }, this.#refreshIntervalMs);
58
+ }
59
+
60
+ stop(): void {
61
+ if (this.#timer !== undefined) {
62
+ clearInterval(this.#timer);
63
+ this.#timer = undefined;
64
+ }
65
+ }
66
+
67
+ getSchedule(): AuthBrokerRefresherSchedule {
68
+ return {
69
+ enabled: true,
70
+ intervalMs: this.#refreshIntervalMs,
71
+ skewMs: this.#refreshSkewMs,
72
+ nextSweepAt: this.#nextSweepAt,
73
+ };
74
+ }
75
+
76
+ /** Run one sweep. Exposed for tests. */
77
+ async tick(): Promise<void> {
78
+ if (this.#running) return;
79
+ this.#running = true;
80
+ this.#nextSweepAt = this.#now();
81
+ try {
82
+ await this.#storage.reload();
83
+ const snapshot = this.#storage.exportSnapshot();
84
+ const now = this.#now();
85
+ const deadline = now + this.#refreshSkewMs;
86
+ const targets: number[] = [];
87
+ for (const entry of snapshot.credentials) {
88
+ if (entry.credential.type !== "oauth") continue;
89
+ const expires = entry.credential.expires;
90
+ if (typeof expires !== "number" || !Number.isFinite(expires)) continue;
91
+ if (expires > deadline) continue;
92
+ targets.push(entry.id);
93
+ }
94
+ await Promise.all(targets.map(id => this.#refreshOne(id)));
95
+ } finally {
96
+ this.#running = false;
97
+ this.#nextSweepAt = this.#now() + this.#refreshIntervalMs;
98
+ }
99
+ }
100
+
101
+ async #refreshOne(id: number): Promise<void> {
102
+ try {
103
+ await this.#storage.refreshCredentialById(id);
104
+ } catch (error) {
105
+ const errorMsg = String(error);
106
+ if (isDefinitiveOAuthFailure(errorMsg)) {
107
+ logger.warn("auth-broker refresh failed definitively; disabling credential", {
108
+ id,
109
+ error: errorMsg,
110
+ });
111
+ this.#storage.disableCredentialById(id, `auth-broker refresh failed: ${errorMsg}`);
112
+ } else {
113
+ logger.debug("auth-broker refresh failed (transient)", { id, error: errorMsg });
114
+ }
115
+ }
116
+ }
117
+ }