ugly-app 0.1.0

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 (554) hide show
  1. package/.claude/settings.local.json +18 -0
  2. package/.env.example +9 -0
  3. package/.yarn-metadata.json +113 -0
  4. package/README.md +709 -0
  5. package/dist/cli/authCommands.d.ts +6 -0
  6. package/dist/cli/authCommands.d.ts.map +1 -0
  7. package/dist/cli/authCommands.js +50 -0
  8. package/dist/cli/authCommands.js.map +1 -0
  9. package/dist/cli/build.d.ts +2 -0
  10. package/dist/cli/build.d.ts.map +1 -0
  11. package/dist/cli/build.js +26 -0
  12. package/dist/cli/build.js.map +1 -0
  13. package/dist/cli/configure.d.ts +2 -0
  14. package/dist/cli/configure.d.ts.map +1 -0
  15. package/dist/cli/configure.js +53 -0
  16. package/dist/cli/configure.js.map +1 -0
  17. package/dist/cli/dev.d.ts +2 -0
  18. package/dist/cli/dev.d.ts.map +1 -0
  19. package/dist/cli/dev.js +66 -0
  20. package/dist/cli/dev.js.map +1 -0
  21. package/dist/cli/index.d.ts +3 -0
  22. package/dist/cli/index.d.ts.map +1 -0
  23. package/dist/cli/index.js +340 -0
  24. package/dist/cli/index.js.map +1 -0
  25. package/dist/cli/initDb.d.ts +2 -0
  26. package/dist/cli/initDb.d.ts.map +1 -0
  27. package/dist/cli/initDb.js +110 -0
  28. package/dist/cli/initDb.js.map +1 -0
  29. package/dist/cli/logQuery.d.ts +12 -0
  30. package/dist/cli/logQuery.d.ts.map +1 -0
  31. package/dist/cli/logQuery.js +176 -0
  32. package/dist/cli/logQuery.js.map +1 -0
  33. package/dist/cli/migrate.d.ts +4 -0
  34. package/dist/cli/migrate.d.ts.map +1 -0
  35. package/dist/cli/migrate.js +62 -0
  36. package/dist/cli/migrate.js.map +1 -0
  37. package/dist/cli/publishAssets.d.ts +6 -0
  38. package/dist/cli/publishAssets.d.ts.map +1 -0
  39. package/dist/cli/publishAssets.js +87 -0
  40. package/dist/cli/publishAssets.js.map +1 -0
  41. package/dist/cli/purgeAssets.d.ts +2 -0
  42. package/dist/cli/purgeAssets.d.ts.map +1 -0
  43. package/dist/cli/purgeAssets.js +36 -0
  44. package/dist/cli/purgeAssets.js.map +1 -0
  45. package/dist/cli/scaffold.d.ts +2 -0
  46. package/dist/cli/scaffold.d.ts.map +1 -0
  47. package/dist/cli/scaffold.js +37 -0
  48. package/dist/cli/scaffold.js.map +1 -0
  49. package/dist/cli/serverLogQuery.d.ts +6 -0
  50. package/dist/cli/serverLogQuery.d.ts.map +1 -0
  51. package/dist/cli/serverLogQuery.js +76 -0
  52. package/dist/cli/serverLogQuery.js.map +1 -0
  53. package/dist/cli/storageClient.d.ts +3 -0
  54. package/dist/cli/storageClient.d.ts.map +1 -0
  55. package/dist/cli/storageClient.js +22 -0
  56. package/dist/cli/storageClient.js.map +1 -0
  57. package/dist/cli/uglyappConfig.d.ts +29 -0
  58. package/dist/cli/uglyappConfig.d.ts.map +1 -0
  59. package/dist/cli/uglyappConfig.js +125 -0
  60. package/dist/cli/uglyappConfig.js.map +1 -0
  61. package/dist/client/AppProvider.d.ts +32 -0
  62. package/dist/client/AppProvider.d.ts.map +1 -0
  63. package/dist/client/AppProvider.js +126 -0
  64. package/dist/client/AppProvider.js.map +1 -0
  65. package/dist/client/ErrorLog.d.ts +16 -0
  66. package/dist/client/ErrorLog.d.ts.map +1 -0
  67. package/dist/client/ErrorLog.js +28 -0
  68. package/dist/client/ErrorLog.js.map +1 -0
  69. package/dist/client/FeedbackContext.d.ts +7 -0
  70. package/dist/client/FeedbackContext.d.ts.map +1 -0
  71. package/dist/client/FeedbackContext.js +15 -0
  72. package/dist/client/FeedbackContext.js.map +1 -0
  73. package/dist/client/Logger.d.ts +2 -0
  74. package/dist/client/Logger.d.ts.map +1 -0
  75. package/dist/client/Logger.js +72 -0
  76. package/dist/client/Logger.js.map +1 -0
  77. package/dist/client/LoginPopup.d.ts +7 -0
  78. package/dist/client/LoginPopup.d.ts.map +1 -0
  79. package/dist/client/LoginPopup.js +55 -0
  80. package/dist/client/LoginPopup.js.map +1 -0
  81. package/dist/client/Router.d.ts +56 -0
  82. package/dist/client/Router.d.ts.map +1 -0
  83. package/dist/client/Router.js +224 -0
  84. package/dist/client/Router.js.map +1 -0
  85. package/dist/client/Screenshot.d.ts +7 -0
  86. package/dist/client/Screenshot.d.ts.map +1 -0
  87. package/dist/client/Screenshot.js +54 -0
  88. package/dist/client/Screenshot.js.map +1 -0
  89. package/dist/client/ViewFlipper.d.ts +16 -0
  90. package/dist/client/ViewFlipper.d.ts.map +1 -0
  91. package/dist/client/ViewFlipper.js +156 -0
  92. package/dist/client/ViewFlipper.js.map +1 -0
  93. package/dist/client/animation/Animated.d.ts +14 -0
  94. package/dist/client/animation/Animated.d.ts.map +1 -0
  95. package/dist/client/animation/Animated.js +97 -0
  96. package/dist/client/animation/Animated.js.map +1 -0
  97. package/dist/client/animation/animatedValue.d.ts +41 -0
  98. package/dist/client/animation/animatedValue.d.ts.map +1 -0
  99. package/dist/client/animation/animatedValue.js +123 -0
  100. package/dist/client/animation/animatedValue.js.map +1 -0
  101. package/dist/client/animations/FadeIn.d.ts +6 -0
  102. package/dist/client/animations/FadeIn.d.ts.map +1 -0
  103. package/dist/client/animations/FadeIn.js +24 -0
  104. package/dist/client/animations/FadeIn.js.map +1 -0
  105. package/dist/client/animations/SlideFromBottom.d.ts +6 -0
  106. package/dist/client/animations/SlideFromBottom.d.ts.map +1 -0
  107. package/dist/client/animations/SlideFromBottom.js +24 -0
  108. package/dist/client/animations/SlideFromBottom.js.map +1 -0
  109. package/dist/client/animations/SlideFromRight.d.ts +6 -0
  110. package/dist/client/animations/SlideFromRight.d.ts.map +1 -0
  111. package/dist/client/animations/SlideFromRight.js +24 -0
  112. package/dist/client/animations/SlideFromRight.js.map +1 -0
  113. package/dist/client/audio/AudioPlayer.d.ts +11 -0
  114. package/dist/client/audio/AudioPlayer.d.ts.map +1 -0
  115. package/dist/client/audio/AudioPlayer.js +51 -0
  116. package/dist/client/audio/AudioPlayer.js.map +1 -0
  117. package/dist/client/audio/AudioRecorder.d.ts +11 -0
  118. package/dist/client/audio/AudioRecorder.d.ts.map +1 -0
  119. package/dist/client/audio/AudioRecorder.js +66 -0
  120. package/dist/client/audio/AudioRecorder.js.map +1 -0
  121. package/dist/client/audio/audioPlayer.worklet.d.ts +2 -0
  122. package/dist/client/audio/audioPlayer.worklet.d.ts.map +1 -0
  123. package/dist/client/audio/audioPlayer.worklet.js +46 -0
  124. package/dist/client/audio/audioPlayer.worklet.js.map +1 -0
  125. package/dist/client/audio/useSTT.d.ts +19 -0
  126. package/dist/client/audio/useSTT.d.ts.map +1 -0
  127. package/dist/client/audio/useSTT.js +91 -0
  128. package/dist/client/audio/useSTT.js.map +1 -0
  129. package/dist/client/audio/useTTS.d.ts +17 -0
  130. package/dist/client/audio/useTTS.d.ts.map +1 -0
  131. package/dist/client/audio/useTTS.js +70 -0
  132. package/dist/client/audio/useTTS.js.map +1 -0
  133. package/dist/client/components/Button.d.ts +22 -0
  134. package/dist/client/components/Button.d.ts.map +1 -0
  135. package/dist/client/components/Button.js +27 -0
  136. package/dist/client/components/Button.js.map +1 -0
  137. package/dist/client/components/Card.d.ts +8 -0
  138. package/dist/client/components/Card.d.ts.map +1 -0
  139. package/dist/client/components/Card.js +6 -0
  140. package/dist/client/components/Card.js.map +1 -0
  141. package/dist/client/components/EnumInput.d.ts +16 -0
  142. package/dist/client/components/EnumInput.d.ts.map +1 -0
  143. package/dist/client/components/EnumInput.js +11 -0
  144. package/dist/client/components/EnumInput.js.map +1 -0
  145. package/dist/client/components/FeedbackButton.d.ts +9 -0
  146. package/dist/client/components/FeedbackButton.d.ts.map +1 -0
  147. package/dist/client/components/FeedbackButton.js +112 -0
  148. package/dist/client/components/FeedbackButton.js.map +1 -0
  149. package/dist/client/components/Header.d.ts +10 -0
  150. package/dist/client/components/Header.d.ts.map +1 -0
  151. package/dist/client/components/Header.js +12 -0
  152. package/dist/client/components/Header.js.map +1 -0
  153. package/dist/client/components/Image.d.ts +20 -0
  154. package/dist/client/components/Image.d.ts.map +1 -0
  155. package/dist/client/components/Image.js +12 -0
  156. package/dist/client/components/Image.js.map +1 -0
  157. package/dist/client/components/Input.d.ts +14 -0
  158. package/dist/client/components/Input.d.ts.map +1 -0
  159. package/dist/client/components/Input.js +19 -0
  160. package/dist/client/components/Input.js.map +1 -0
  161. package/dist/client/components/Modal.d.ts +9 -0
  162. package/dist/client/components/Modal.d.ts.map +1 -0
  163. package/dist/client/components/Modal.js +19 -0
  164. package/dist/client/components/Modal.js.map +1 -0
  165. package/dist/client/components/PageLayout.d.ts +9 -0
  166. package/dist/client/components/PageLayout.d.ts.map +1 -0
  167. package/dist/client/components/PageLayout.js +6 -0
  168. package/dist/client/components/PageLayout.js.map +1 -0
  169. package/dist/client/components/Panel.d.ts +8 -0
  170. package/dist/client/components/Panel.d.ts.map +1 -0
  171. package/dist/client/components/Panel.js +5 -0
  172. package/dist/client/components/Panel.js.map +1 -0
  173. package/dist/client/components/PopupPanel.d.ts +9 -0
  174. package/dist/client/components/PopupPanel.d.ts.map +1 -0
  175. package/dist/client/components/PopupPanel.js +5 -0
  176. package/dist/client/components/PopupPanel.js.map +1 -0
  177. package/dist/client/components/Pressable.d.ts +14 -0
  178. package/dist/client/components/Pressable.d.ts.map +1 -0
  179. package/dist/client/components/Pressable.js +8 -0
  180. package/dist/client/components/Pressable.js.map +1 -0
  181. package/dist/client/components/ScrollView.d.ts +9 -0
  182. package/dist/client/components/ScrollView.d.ts.map +1 -0
  183. package/dist/client/components/ScrollView.js +7 -0
  184. package/dist/client/components/ScrollView.js.map +1 -0
  185. package/dist/client/components/SettingGroup.d.ts +10 -0
  186. package/dist/client/components/SettingGroup.d.ts.map +1 -0
  187. package/dist/client/components/SettingGroup.js +8 -0
  188. package/dist/client/components/SettingGroup.js.map +1 -0
  189. package/dist/client/components/Text.d.ts +21 -0
  190. package/dist/client/components/Text.d.ts.map +1 -0
  191. package/dist/client/components/Text.js +43 -0
  192. package/dist/client/components/Text.js.map +1 -0
  193. package/dist/client/components/Toast.d.ts +10 -0
  194. package/dist/client/components/Toast.d.ts.map +1 -0
  195. package/dist/client/components/Toast.js +21 -0
  196. package/dist/client/components/Toast.js.map +1 -0
  197. package/dist/client/components/View.d.ts +9 -0
  198. package/dist/client/components/View.d.ts.map +1 -0
  199. package/dist/client/components/View.js +5 -0
  200. package/dist/client/components/View.js.map +1 -0
  201. package/dist/client/components/index.d.ts +33 -0
  202. package/dist/client/components/index.d.ts.map +1 -0
  203. package/dist/client/components/index.js +17 -0
  204. package/dist/client/components/index.js.map +1 -0
  205. package/dist/client/components/zIndex.d.ts +10 -0
  206. package/dist/client/components/zIndex.d.ts.map +1 -0
  207. package/dist/client/components/zIndex.js +12 -0
  208. package/dist/client/components/zIndex.js.map +1 -0
  209. package/dist/client/createSocket.d.ts +26 -0
  210. package/dist/client/createSocket.d.ts.map +1 -0
  211. package/dist/client/createSocket.js +138 -0
  212. package/dist/client/createSocket.js.map +1 -0
  213. package/dist/client/index.d.ts +27 -0
  214. package/dist/client/index.d.ts.map +1 -0
  215. package/dist/client/index.js +20 -0
  216. package/dist/client/index.js.map +1 -0
  217. package/dist/playwright/index.d.ts +16 -0
  218. package/dist/playwright/index.d.ts.map +1 -0
  219. package/dist/playwright/index.js +32 -0
  220. package/dist/playwright/index.js.map +1 -0
  221. package/dist/server/App.d.ts +43 -0
  222. package/dist/server/App.d.ts.map +1 -0
  223. package/dist/server/App.js +215 -0
  224. package/dist/server/App.js.map +1 -0
  225. package/dist/server/Auth.d.ts +21 -0
  226. package/dist/server/Auth.d.ts.map +1 -0
  227. package/dist/server/Auth.js +171 -0
  228. package/dist/server/Auth.js.map +1 -0
  229. package/dist/server/Cache.d.ts +38 -0
  230. package/dist/server/Cache.d.ts.map +1 -0
  231. package/dist/server/Cache.js +113 -0
  232. package/dist/server/Cache.js.map +1 -0
  233. package/dist/server/ChangeStream.d.ts +22 -0
  234. package/dist/server/ChangeStream.d.ts.map +1 -0
  235. package/dist/server/ChangeStream.js +93 -0
  236. package/dist/server/ChangeStream.js.map +1 -0
  237. package/dist/server/DB.d.ts +17 -0
  238. package/dist/server/DB.d.ts.map +1 -0
  239. package/dist/server/DB.js +442 -0
  240. package/dist/server/DB.js.map +1 -0
  241. package/dist/server/Email.d.ts +22 -0
  242. package/dist/server/Email.d.ts.map +1 -0
  243. package/dist/server/Email.js +64 -0
  244. package/dist/server/Email.js.map +1 -0
  245. package/dist/server/EmailTemplate.d.ts +17 -0
  246. package/dist/server/EmailTemplate.d.ts.map +1 -0
  247. package/dist/server/EmailTemplate.js +29 -0
  248. package/dist/server/EmailTemplate.js.map +1 -0
  249. package/dist/server/FeedbackReport.d.ts +19 -0
  250. package/dist/server/FeedbackReport.d.ts.map +1 -0
  251. package/dist/server/FeedbackReport.js +94 -0
  252. package/dist/server/FeedbackReport.js.map +1 -0
  253. package/dist/server/ImageGen.d.ts +5 -0
  254. package/dist/server/ImageGen.d.ts.map +1 -0
  255. package/dist/server/ImageGen.js +5 -0
  256. package/dist/server/ImageGen.js.map +1 -0
  257. package/dist/server/Logging.d.ts +59 -0
  258. package/dist/server/Logging.d.ts.map +1 -0
  259. package/dist/server/Logging.js +293 -0
  260. package/dist/server/Logging.js.map +1 -0
  261. package/dist/server/Nats.d.ts +56 -0
  262. package/dist/server/Nats.d.ts.map +1 -0
  263. package/dist/server/Nats.js +162 -0
  264. package/dist/server/Nats.js.map +1 -0
  265. package/dist/server/NatsStore.d.ts +26 -0
  266. package/dist/server/NatsStore.d.ts.map +1 -0
  267. package/dist/server/NatsStore.js +86 -0
  268. package/dist/server/NatsStore.js.map +1 -0
  269. package/dist/server/PushNotification.d.ts +33 -0
  270. package/dist/server/PushNotification.d.ts.map +1 -0
  271. package/dist/server/PushNotification.js +131 -0
  272. package/dist/server/PushNotification.js.map +1 -0
  273. package/dist/server/RateLimit.d.ts +28 -0
  274. package/dist/server/RateLimit.d.ts.map +1 -0
  275. package/dist/server/RateLimit.js +101 -0
  276. package/dist/server/RateLimit.js.map +1 -0
  277. package/dist/server/Redis.d.ts +61 -0
  278. package/dist/server/Redis.d.ts.map +1 -0
  279. package/dist/server/Redis.js +226 -0
  280. package/dist/server/Redis.js.map +1 -0
  281. package/dist/server/Router.d.ts +27 -0
  282. package/dist/server/Router.d.ts.map +1 -0
  283. package/dist/server/Router.js +71 -0
  284. package/dist/server/Router.js.map +1 -0
  285. package/dist/server/Socket.d.ts +8 -0
  286. package/dist/server/Socket.d.ts.map +1 -0
  287. package/dist/server/Socket.js +278 -0
  288. package/dist/server/Socket.js.map +1 -0
  289. package/dist/server/SpendTracker.d.ts +18 -0
  290. package/dist/server/SpendTracker.d.ts.map +1 -0
  291. package/dist/server/SpendTracker.js +110 -0
  292. package/dist/server/SpendTracker.js.map +1 -0
  293. package/dist/server/Storage.d.ts +16 -0
  294. package/dist/server/Storage.d.ts.map +1 -0
  295. package/dist/server/Storage.js +95 -0
  296. package/dist/server/Storage.js.map +1 -0
  297. package/dist/server/TextGen.d.ts +5 -0
  298. package/dist/server/TextGen.d.ts.map +1 -0
  299. package/dist/server/TextGen.js +6 -0
  300. package/dist/server/TextGen.js.map +1 -0
  301. package/dist/server/WorkerQueue.d.ts +27 -0
  302. package/dist/server/WorkerQueue.d.ts.map +1 -0
  303. package/dist/server/WorkerQueue.js +147 -0
  304. package/dist/server/WorkerQueue.js.map +1 -0
  305. package/dist/server/ai/ImageGenClient.d.ts +6 -0
  306. package/dist/server/ai/ImageGenClient.d.ts.map +1 -0
  307. package/dist/server/ai/ImageGenClient.js +29 -0
  308. package/dist/server/ai/ImageGenClient.js.map +1 -0
  309. package/dist/server/ai/ProviderBalance.d.ts +15 -0
  310. package/dist/server/ai/ProviderBalance.d.ts.map +1 -0
  311. package/dist/server/ai/ProviderBalance.js +110 -0
  312. package/dist/server/ai/ProviderBalance.js.map +1 -0
  313. package/dist/server/ai/ProviderSelector.d.ts +13 -0
  314. package/dist/server/ai/ProviderSelector.d.ts.map +1 -0
  315. package/dist/server/ai/ProviderSelector.js +25 -0
  316. package/dist/server/ai/ProviderSelector.js.map +1 -0
  317. package/dist/server/ai/TextGenClient.d.ts +9 -0
  318. package/dist/server/ai/TextGenClient.d.ts.map +1 -0
  319. package/dist/server/ai/TextGenClient.js +72 -0
  320. package/dist/server/ai/TextGenClient.js.map +1 -0
  321. package/dist/server/ai/fallbacks.d.ts +9 -0
  322. package/dist/server/ai/fallbacks.d.ts.map +1 -0
  323. package/dist/server/ai/fallbacks.js +77 -0
  324. package/dist/server/ai/fallbacks.js.map +1 -0
  325. package/dist/server/ai/index.d.ts +12 -0
  326. package/dist/server/ai/index.d.ts.map +1 -0
  327. package/dist/server/ai/index.js +37 -0
  328. package/dist/server/ai/index.js.map +1 -0
  329. package/dist/server/ai/providers/Claude.d.ts +3 -0
  330. package/dist/server/ai/providers/Claude.d.ts.map +1 -0
  331. package/dist/server/ai/providers/Claude.js +124 -0
  332. package/dist/server/ai/providers/Claude.js.map +1 -0
  333. package/dist/server/ai/providers/FAL.d.ts +3 -0
  334. package/dist/server/ai/providers/FAL.d.ts.map +1 -0
  335. package/dist/server/ai/providers/FAL.js +24 -0
  336. package/dist/server/ai/providers/FAL.js.map +1 -0
  337. package/dist/server/ai/providers/Fireworks.d.ts +3 -0
  338. package/dist/server/ai/providers/Fireworks.d.ts.map +1 -0
  339. package/dist/server/ai/providers/Fireworks.js +79 -0
  340. package/dist/server/ai/providers/Fireworks.js.map +1 -0
  341. package/dist/server/ai/providers/Google.d.ts +3 -0
  342. package/dist/server/ai/providers/Google.d.ts.map +1 -0
  343. package/dist/server/ai/providers/Google.js +105 -0
  344. package/dist/server/ai/providers/Google.js.map +1 -0
  345. package/dist/server/ai/providers/GoogleImage.d.ts +3 -0
  346. package/dist/server/ai/providers/GoogleImage.d.ts.map +1 -0
  347. package/dist/server/ai/providers/GoogleImage.js +24 -0
  348. package/dist/server/ai/providers/GoogleImage.js.map +1 -0
  349. package/dist/server/ai/providers/Groq.d.ts +3 -0
  350. package/dist/server/ai/providers/Groq.d.ts.map +1 -0
  351. package/dist/server/ai/providers/Groq.js +99 -0
  352. package/dist/server/ai/providers/Groq.js.map +1 -0
  353. package/dist/server/ai/providers/Kie.d.ts +3 -0
  354. package/dist/server/ai/providers/Kie.d.ts.map +1 -0
  355. package/dist/server/ai/providers/Kie.js +79 -0
  356. package/dist/server/ai/providers/Kie.js.map +1 -0
  357. package/dist/server/ai/providers/KieImage.d.ts +3 -0
  358. package/dist/server/ai/providers/KieImage.d.ts.map +1 -0
  359. package/dist/server/ai/providers/KieImage.js +50 -0
  360. package/dist/server/ai/providers/KieImage.js.map +1 -0
  361. package/dist/server/ai/providers/OpenAIText.d.ts +3 -0
  362. package/dist/server/ai/providers/OpenAIText.d.ts.map +1 -0
  363. package/dist/server/ai/providers/OpenAIText.js +103 -0
  364. package/dist/server/ai/providers/OpenAIText.js.map +1 -0
  365. package/dist/server/ai/providers/Together.d.ts +3 -0
  366. package/dist/server/ai/providers/Together.d.ts.map +1 -0
  367. package/dist/server/ai/providers/Together.js +99 -0
  368. package/dist/server/ai/providers/Together.js.map +1 -0
  369. package/dist/server/ai/providers/TogetherImage.d.ts +3 -0
  370. package/dist/server/ai/providers/TogetherImage.d.ts.map +1 -0
  371. package/dist/server/ai/providers/TogetherImage.js +24 -0
  372. package/dist/server/ai/providers/TogetherImage.js.map +1 -0
  373. package/dist/server/ai/providers/Wavespeed.d.ts +3 -0
  374. package/dist/server/ai/providers/Wavespeed.d.ts.map +1 -0
  375. package/dist/server/ai/providers/Wavespeed.js +53 -0
  376. package/dist/server/ai/providers/Wavespeed.js.map +1 -0
  377. package/dist/server/ai/registry.d.ts +10 -0
  378. package/dist/server/ai/registry.d.ts.map +1 -0
  379. package/dist/server/ai/registry.js +26 -0
  380. package/dist/server/ai/registry.js.map +1 -0
  381. package/dist/server/ai/types.d.ts +67 -0
  382. package/dist/server/ai/types.d.ts.map +1 -0
  383. package/dist/server/ai/types.js +17 -0
  384. package/dist/server/ai/types.js.map +1 -0
  385. package/dist/server/audio/STTStream.d.ts +12 -0
  386. package/dist/server/audio/STTStream.d.ts.map +1 -0
  387. package/dist/server/audio/STTStream.js +59 -0
  388. package/dist/server/audio/STTStream.js.map +1 -0
  389. package/dist/server/audio/TTSStream.d.ts +16 -0
  390. package/dist/server/audio/TTSStream.d.ts.map +1 -0
  391. package/dist/server/audio/TTSStream.js +151 -0
  392. package/dist/server/audio/TTSStream.js.map +1 -0
  393. package/dist/server/audio/index.d.ts +5 -0
  394. package/dist/server/audio/index.d.ts.map +1 -0
  395. package/dist/server/audio/index.js +14 -0
  396. package/dist/server/audio/index.js.map +1 -0
  397. package/dist/server/audio/resample.d.ts +7 -0
  398. package/dist/server/audio/resample.d.ts.map +1 -0
  399. package/dist/server/audio/resample.js +17 -0
  400. package/dist/server/audio/resample.js.map +1 -0
  401. package/dist/server/audio/stt/GroqWhisper.d.ts +3 -0
  402. package/dist/server/audio/stt/GroqWhisper.d.ts.map +1 -0
  403. package/dist/server/audio/stt/GroqWhisper.js +91 -0
  404. package/dist/server/audio/stt/GroqWhisper.js.map +1 -0
  405. package/dist/server/audio/stt/registry.d.ts +5 -0
  406. package/dist/server/audio/stt/registry.d.ts.map +1 -0
  407. package/dist/server/audio/stt/registry.js +11 -0
  408. package/dist/server/audio/stt/registry.js.map +1 -0
  409. package/dist/server/audio/stt/types.d.ts +25 -0
  410. package/dist/server/audio/stt/types.d.ts.map +1 -0
  411. package/dist/server/audio/stt/types.js +2 -0
  412. package/dist/server/audio/stt/types.js.map +1 -0
  413. package/dist/server/audio/stt/vad.d.ts +18 -0
  414. package/dist/server/audio/stt/vad.d.ts.map +1 -0
  415. package/dist/server/audio/stt/vad.js +90 -0
  416. package/dist/server/audio/stt/vad.js.map +1 -0
  417. package/dist/server/audio/tts/InWorld.d.ts +3 -0
  418. package/dist/server/audio/tts/InWorld.d.ts.map +1 -0
  419. package/dist/server/audio/tts/InWorld.js +147 -0
  420. package/dist/server/audio/tts/InWorld.js.map +1 -0
  421. package/dist/server/audio/tts/providers/Azure.d.ts +3 -0
  422. package/dist/server/audio/tts/providers/Azure.d.ts.map +1 -0
  423. package/dist/server/audio/tts/providers/Azure.js +31 -0
  424. package/dist/server/audio/tts/providers/Azure.js.map +1 -0
  425. package/dist/server/audio/tts/registry.d.ts +6 -0
  426. package/dist/server/audio/tts/registry.d.ts.map +1 -0
  427. package/dist/server/audio/tts/registry.js +12 -0
  428. package/dist/server/audio/tts/registry.js.map +1 -0
  429. package/dist/server/audio/tts/types.d.ts +20 -0
  430. package/dist/server/audio/tts/types.d.ts.map +1 -0
  431. package/dist/server/audio/tts/types.js +2 -0
  432. package/dist/server/audio/tts/types.js.map +1 -0
  433. package/dist/server/billing/BillingGateway.d.ts +40 -0
  434. package/dist/server/billing/BillingGateway.d.ts.map +1 -0
  435. package/dist/server/billing/BillingGateway.js +116 -0
  436. package/dist/server/billing/BillingGateway.js.map +1 -0
  437. package/dist/server/billing/BillingLedger.d.ts +67 -0
  438. package/dist/server/billing/BillingLedger.d.ts.map +1 -0
  439. package/dist/server/billing/BillingLedger.js +214 -0
  440. package/dist/server/billing/BillingLedger.js.map +1 -0
  441. package/dist/server/billing/CreditStore.d.ts +58 -0
  442. package/dist/server/billing/CreditStore.d.ts.map +1 -0
  443. package/dist/server/billing/CreditStore.js +112 -0
  444. package/dist/server/billing/CreditStore.js.map +1 -0
  445. package/dist/server/billing/LimitEnforcer.d.ts +73 -0
  446. package/dist/server/billing/LimitEnforcer.d.ts.map +1 -0
  447. package/dist/server/billing/LimitEnforcer.js +276 -0
  448. package/dist/server/billing/LimitEnforcer.js.map +1 -0
  449. package/dist/server/billing/UserLimitCache.d.ts +35 -0
  450. package/dist/server/billing/UserLimitCache.d.ts.map +1 -0
  451. package/dist/server/billing/UserLimitCache.js +91 -0
  452. package/dist/server/billing/UserLimitCache.js.map +1 -0
  453. package/dist/server/billing/index.d.ts +6 -0
  454. package/dist/server/billing/index.d.ts.map +1 -0
  455. package/dist/server/billing/index.js +4 -0
  456. package/dist/server/billing/index.js.map +1 -0
  457. package/dist/server/billing/types.d.ts +95 -0
  458. package/dist/server/billing/types.d.ts.map +1 -0
  459. package/dist/server/billing/types.js +19 -0
  460. package/dist/server/billing/types.js.map +1 -0
  461. package/dist/server/embeddings/EmbeddingClient.d.ts +8 -0
  462. package/dist/server/embeddings/EmbeddingClient.d.ts.map +1 -0
  463. package/dist/server/embeddings/EmbeddingClient.js +30 -0
  464. package/dist/server/embeddings/EmbeddingClient.js.map +1 -0
  465. package/dist/server/embeddings/index.d.ts +5 -0
  466. package/dist/server/embeddings/index.d.ts.map +1 -0
  467. package/dist/server/embeddings/index.js +6 -0
  468. package/dist/server/embeddings/index.js.map +1 -0
  469. package/dist/server/embeddings/providers/OpenAI.d.ts +3 -0
  470. package/dist/server/embeddings/providers/OpenAI.d.ts.map +1 -0
  471. package/dist/server/embeddings/providers/OpenAI.js +28 -0
  472. package/dist/server/embeddings/providers/OpenAI.js.map +1 -0
  473. package/dist/server/embeddings/registry.d.ts +7 -0
  474. package/dist/server/embeddings/registry.d.ts.map +1 -0
  475. package/dist/server/embeddings/registry.js +15 -0
  476. package/dist/server/embeddings/registry.js.map +1 -0
  477. package/dist/server/embeddings/types.d.ts +12 -0
  478. package/dist/server/embeddings/types.d.ts.map +1 -0
  479. package/dist/server/embeddings/types.js +2 -0
  480. package/dist/server/embeddings/types.js.map +1 -0
  481. package/dist/server/index.d.ts +59 -0
  482. package/dist/server/index.d.ts.map +1 -0
  483. package/dist/server/index.js +41 -0
  484. package/dist/server/index.js.map +1 -0
  485. package/dist/shared/Api.d.ts +40 -0
  486. package/dist/shared/Api.d.ts.map +1 -0
  487. package/dist/shared/Api.js +30 -0
  488. package/dist/shared/Api.js.map +1 -0
  489. package/dist/shared/Audio.d.ts +108 -0
  490. package/dist/shared/Audio.d.ts.map +1 -0
  491. package/dist/shared/Audio.js +3 -0
  492. package/dist/shared/Audio.js.map +1 -0
  493. package/dist/shared/DB.d.ts +339 -0
  494. package/dist/shared/DB.d.ts.map +1 -0
  495. package/dist/shared/DB.js +51 -0
  496. package/dist/shared/DB.js.map +1 -0
  497. package/dist/shared/Errors.d.ts +10 -0
  498. package/dist/shared/Errors.d.ts.map +1 -0
  499. package/dist/shared/Errors.js +19 -0
  500. package/dist/shared/Errors.js.map +1 -0
  501. package/dist/shared/FeedbackReport.d.ts +38 -0
  502. package/dist/shared/FeedbackReport.d.ts.map +1 -0
  503. package/dist/shared/FeedbackReport.js +14 -0
  504. package/dist/shared/FeedbackReport.js.map +1 -0
  505. package/dist/shared/Router.d.ts +28 -0
  506. package/dist/shared/Router.d.ts.map +1 -0
  507. package/dist/shared/Router.js +82 -0
  508. package/dist/shared/Router.js.map +1 -0
  509. package/dist/shared/Socket.d.ts +26 -0
  510. package/dist/shared/Socket.d.ts.map +1 -0
  511. package/dist/shared/Socket.js +2 -0
  512. package/dist/shared/Socket.js.map +1 -0
  513. package/dist/shared/index.d.ts +28 -0
  514. package/dist/shared/index.d.ts.map +1 -0
  515. package/dist/shared/index.js +61 -0
  516. package/dist/shared/index.js.map +1 -0
  517. package/dist/webrtc/index.d.ts +14 -0
  518. package/dist/webrtc/index.d.ts.map +1 -0
  519. package/dist/webrtc/index.js +24 -0
  520. package/dist/webrtc/index.js.map +1 -0
  521. package/package.json +97 -0
  522. package/templates/.claude/skills/assets.md +39 -0
  523. package/templates/.claude/skills/check-errors.md +35 -0
  524. package/templates/.claude/skills/check-feedback.md +23 -0
  525. package/templates/.claude/skills/check-perf.md +22 -0
  526. package/templates/.claude/skills/create-test-users.md +34 -0
  527. package/templates/.claude/skills/extend-api.md +37 -0
  528. package/templates/.claude/skills/fix-code.md +5 -0
  529. package/templates/.claude/skills/fix-errors.md +9 -0
  530. package/templates/.claude/skills/fix-feedback.md +8 -0
  531. package/templates/.claude/skills/fix-perf.md +8 -0
  532. package/templates/.claude/skills/uploads.md +38 -0
  533. package/templates/.claude/skills/use-ai.md +49 -0
  534. package/templates/.env.example +49 -0
  535. package/templates/.husky/pre-commit +2 -0
  536. package/templates/CLAUDE.md +199 -0
  537. package/templates/client/App.tsx +33 -0
  538. package/templates/client/index.html +14 -0
  539. package/templates/client/main.tsx +52 -0
  540. package/templates/client/pages/AuthDemoPage.tsx +85 -0
  541. package/templates/client/pages/HomePage.tsx +111 -0
  542. package/templates/client/pages/SearchPage.tsx +48 -0
  543. package/templates/client/pages/UserPage.tsx +33 -0
  544. package/templates/client/router.ts +4 -0
  545. package/templates/docker-compose.yml +50 -0
  546. package/templates/index.html +14 -0
  547. package/templates/package.json +56 -0
  548. package/templates/playwright.config.ts +21 -0
  549. package/templates/server/index.ts +24 -0
  550. package/templates/shared/api.ts +36 -0
  551. package/templates/shared/collections.ts +11 -0
  552. package/templates/shared/dbIndexes.ts +11 -0
  553. package/templates/shared/pages.ts +8 -0
  554. package/templates/vite.config.ts +17 -0
@@ -0,0 +1,214 @@
1
+ const HOUR_MS = 3_600_000;
2
+ // ---------------------------------------------------------------------------
3
+ // BillingLedger
4
+ // ---------------------------------------------------------------------------
5
+ export class BillingLedger {
6
+ db;
7
+ reconcileIntervalMs;
8
+ pending = [];
9
+ timer = null;
10
+ constructor(db, reconcileIntervalMs = 300_000) {
11
+ this.db = db;
12
+ this.reconcileIntervalMs = reconcileIntervalMs;
13
+ }
14
+ /** Expose pending buffer size (for testing). */
15
+ pendingCount() {
16
+ return this.pending.length;
17
+ }
18
+ /** Synchronously append a record to the in-memory buffer. */
19
+ add(record) {
20
+ const stored = {
21
+ id: record.id,
22
+ version: 1,
23
+ created: new Date(record.timestamp),
24
+ updated: new Date(record.timestamp),
25
+ userId: record.userId,
26
+ provider: record.provider,
27
+ model: record.model,
28
+ type: record.type,
29
+ costUsd: record.costUsd,
30
+ inputTokens: record.inputTokens,
31
+ outputTokens: record.outputTokens,
32
+ imageCount: record.imageCount,
33
+ imageWidth: record.imageWidth,
34
+ imageHeight: record.imageHeight,
35
+ imageSteps: record.imageSteps,
36
+ audioSeconds: record.audioSeconds,
37
+ timestamp: record.timestamp,
38
+ };
39
+ this.pending.push(stored);
40
+ }
41
+ /**
42
+ * Sum costUsd for records in [now-windowMs, now], combining DB + in-memory pending.
43
+ * Pending records are NOT in DB yet — no double-counting.
44
+ */
45
+ async getWindowSpend(windowMs, filters) {
46
+ const now = Date.now();
47
+ const from = filters?.from ?? now - windowMs;
48
+ const to = filters?.to ?? now;
49
+ const filter = {
50
+ timestamp: { $gte: from, $lte: to },
51
+ };
52
+ if (filters?.userId !== undefined)
53
+ filter.userId = filters.userId;
54
+ if (filters?.provider !== undefined)
55
+ filter.provider = filters.provider;
56
+ if (filters?.type !== undefined)
57
+ filter.type = filters.type;
58
+ const dbRecords = await this.db.getDocs(filter, {});
59
+ const dbTotal = dbRecords.reduce((sum, r) => sum + r.costUsd, 0);
60
+ const pendingTotal = this.pending
61
+ .filter((r) => {
62
+ if (r.timestamp < from || r.timestamp > to)
63
+ return false;
64
+ if (filters?.userId !== undefined && r.userId !== filters.userId)
65
+ return false;
66
+ if (filters?.provider !== undefined && r.provider !== filters.provider)
67
+ return false;
68
+ if (filters?.type !== undefined && r.type !== filters.type)
69
+ return false;
70
+ return true;
71
+ })
72
+ .reduce((sum, r) => sum + r.costUsd, 0);
73
+ return dbTotal + pendingTotal;
74
+ }
75
+ /**
76
+ * Upsert all pending records to MongoDB, then clear the buffer.
77
+ * Atomic snapshot: concurrent adds after the snapshot are safe.
78
+ * On failure: failed records are prepended back to pending.
79
+ */
80
+ async reconcile() {
81
+ if (this.pending.length === 0)
82
+ return;
83
+ // Atomic snapshot
84
+ const toWrite = this.pending;
85
+ this.pending = [];
86
+ const failed = [];
87
+ for (const record of toWrite) {
88
+ try {
89
+ await this.db.setDoc(record.id, record);
90
+ }
91
+ catch (err) {
92
+ failed.push(record);
93
+ console.error('[BillingLedger] Failed to reconcile record', record.id, err);
94
+ }
95
+ }
96
+ if (failed.length > 0) {
97
+ // Prepend failed records so they're retried first next cycle
98
+ this.pending = [...failed, ...this.pending];
99
+ }
100
+ if (this.pending.length > 1000) {
101
+ console.warn('[BillingLedger] pending buffer exceeds 1000 records', {
102
+ pendingCount: this.pending.length,
103
+ });
104
+ }
105
+ }
106
+ /**
107
+ * Query billing history merging DB records and in-memory pending.
108
+ * Sorted by timestamp DESC, id ASC. Limit/skip applied to merged result.
109
+ */
110
+ async getHistory(filters = {}) {
111
+ const limit = Math.min(filters.limit ?? 100, 1000);
112
+ const skip = filters.skip ?? 0;
113
+ const filter = {};
114
+ if (filters.from !== undefined || filters.to !== undefined) {
115
+ filter.timestamp = {};
116
+ if (filters.from !== undefined)
117
+ filter.timestamp['$gte'] = filters.from;
118
+ if (filters.to !== undefined)
119
+ filter.timestamp['$lte'] = filters.to;
120
+ }
121
+ if (filters.userId !== undefined)
122
+ filter.userId = filters.userId;
123
+ if (filters.provider !== undefined)
124
+ filter.provider = filters.provider;
125
+ if (filters.type !== undefined)
126
+ filter.type = filters.type;
127
+ // Fetch more from DB than requested to account for pending records shifting pagination
128
+ const dbRecords = await this.db.getDocs(filter, {
129
+ sort: { timestamp: -1, id: 1 },
130
+ limit: limit + this.pending.length + skip,
131
+ });
132
+ const pendingMatched = this.pending.filter((r) => {
133
+ if (filters.from !== undefined && r.timestamp < filters.from)
134
+ return false;
135
+ if (filters.to !== undefined && r.timestamp > filters.to)
136
+ return false;
137
+ if (filters.userId !== undefined && r.userId !== filters.userId)
138
+ return false;
139
+ if (filters.provider !== undefined && r.provider !== filters.provider)
140
+ return false;
141
+ if (filters.type !== undefined && r.type !== filters.type)
142
+ return false;
143
+ return true;
144
+ });
145
+ // Merge DB + pending: DB records don't include pending (not yet written)
146
+ const all = [
147
+ ...dbRecords.map(storedToPublic),
148
+ ...pendingMatched.map(storedToPublic),
149
+ ];
150
+ // Sort by timestamp DESC, then id ASC as tiebreaker
151
+ all.sort((a, b) => {
152
+ const tsDiff = b.timestamp - a.timestamp;
153
+ if (tsDiff !== 0)
154
+ return tsDiff;
155
+ return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
156
+ });
157
+ return all.slice(skip, skip + limit);
158
+ }
159
+ /** Start the periodic reconcile timer. */
160
+ start() {
161
+ if (this.timer)
162
+ return;
163
+ this.timer = setInterval(() => {
164
+ void this.reconcile();
165
+ }, this.reconcileIntervalMs);
166
+ }
167
+ /** Stop the timer and flush pending records to DB. */
168
+ async shutdown() {
169
+ if (this.timer) {
170
+ clearInterval(this.timer);
171
+ this.timer = null;
172
+ }
173
+ await this.reconcile();
174
+ }
175
+ }
176
+ // ---------------------------------------------------------------------------
177
+ // Internal helpers
178
+ // ---------------------------------------------------------------------------
179
+ function storedToPublic(r) {
180
+ const record = {
181
+ id: r.id,
182
+ provider: r.provider,
183
+ model: r.model,
184
+ type: r.type,
185
+ costUsd: r.costUsd,
186
+ timestamp: r.timestamp,
187
+ };
188
+ if (r.userId !== undefined)
189
+ record.userId = r.userId;
190
+ if (r.inputTokens !== undefined)
191
+ record.inputTokens = r.inputTokens;
192
+ if (r.outputTokens !== undefined)
193
+ record.outputTokens = r.outputTokens;
194
+ if (r.imageCount !== undefined)
195
+ record.imageCount = r.imageCount;
196
+ if (r.imageWidth !== undefined)
197
+ record.imageWidth = r.imageWidth;
198
+ if (r.imageHeight !== undefined)
199
+ record.imageHeight = r.imageHeight;
200
+ if (r.imageSteps !== undefined)
201
+ record.imageSteps = r.imageSteps;
202
+ if (r.audioSeconds !== undefined)
203
+ record.audioSeconds = r.audioSeconds;
204
+ return record;
205
+ }
206
+ // ---------------------------------------------------------------------------
207
+ // Convenience: how many ms in each window
208
+ // ---------------------------------------------------------------------------
209
+ export const WINDOW_MS = {
210
+ HOUR: HOUR_MS,
211
+ DAY: 24 * HOUR_MS,
212
+ WEEK: 7 * 24 * HOUR_MS,
213
+ };
214
+ //# sourceMappingURL=BillingLedger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BillingLedger.js","sourceRoot":"","sources":["../../../src/server/billing/BillingLedger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ import type { UserCredit } from './types.js';
2
+ export interface CreditDB {
3
+ /** Atomically increment balanceUsd by delta (may be negative). Returns new balance. */
4
+ incrementCredit(userId: string, deltaUsd: number): Promise<number>;
5
+ /** Get current balance. Returns 0 if no record exists. */
6
+ getCredit(userId: string): Promise<number>;
7
+ }
8
+ /**
9
+ * Manages pre-paid credit balances for users.
10
+ *
11
+ * Credits are stored in MongoDB (`userCredits` collection) and cached in-memory
12
+ * with a short TTL. Deductions use optimistic in-memory decrement + async DB write;
13
+ * grants are written directly to DB and then invalidate the cache.
14
+ */
15
+ export declare class CreditStore {
16
+ private readonly db;
17
+ private readonly cache;
18
+ private readonly ttlMs;
19
+ private readonly maxSize;
20
+ constructor(db: CreditDB, ttlMs?: number, // 1 hour
21
+ maxSize?: number);
22
+ /**
23
+ * Grant credits to a user (additive). Writes directly to DB; invalidates cache.
24
+ * Safe to call multiple times — amounts are accumulated.
25
+ */
26
+ grant(userId: string, amountUsd: number): Promise<void>;
27
+ /**
28
+ * Get current credit balance (cached with TTL).
29
+ */
30
+ getBalance(userId: string): Promise<number>;
31
+ /**
32
+ * Attempt to deduct costUsd from the user's credit balance.
33
+ * Returns true if deducted successfully, false if balance is insufficient.
34
+ * Uses optimistic in-memory decrement; DB write is async (fire-and-forget with logging).
35
+ */
36
+ tryDeduct(userId: string, costUsd: number): Promise<boolean>;
37
+ /** Invalidate cached balance for a user (e.g. after external grant). */
38
+ invalidate(userId: string): void;
39
+ private setCache;
40
+ }
41
+ export interface CreditDocDB {
42
+ /** Upsert a userCredits document. */
43
+ setDoc(id: string, doc: UserCredit): Promise<void>;
44
+ /** Get a userCredits document by id. */
45
+ getDoc(id: string): Promise<UserCredit | null>;
46
+ }
47
+ /**
48
+ * MongoDB-backed CreditDB implementation.
49
+ * Uses findOneAndUpdate-style atomic increment via a helper that performs
50
+ * a read-modify-write with the document's balanceUsd field.
51
+ */
52
+ export declare class MongoCreditDB implements CreditDB {
53
+ private readonly db;
54
+ constructor(db: CreditDocDB);
55
+ incrementCredit(userId: string, deltaUsd: number): Promise<number>;
56
+ getCredit(userId: string): Promise<number>;
57
+ }
58
+ //# sourceMappingURL=CreditStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CreditStore.d.ts","sourceRoot":"","sources":["../../../src/server/billing/CreditStore.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAM7C,MAAM,WAAW,QAAQ;IACvB,uFAAuF;IACvF,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACnE,0DAA0D;IAC1D,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC5C;AAWD;;;;;;GAMG;AACH,qBAAa,WAAW;IAMpB,OAAO,CAAC,QAAQ,CAAC,EAAE;IALrB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiC;IACvD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAGd,EAAE,EAAE,QAAQ,EAC7B,KAAK,SAAY,EAAE,SAAS;IAC5B,OAAO,SAAS;IAMlB;;;OAGG;IACG,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAY7D;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAUjD;;;;OAIG;IACG,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IA4BlE,wEAAwE;IACxE,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAQhC,OAAO,CAAC,QAAQ;CAQjB;AAMD,MAAM,WAAW,WAAW;IAC1B,qCAAqC;IACrC,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,wCAAwC;IACxC,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;CAChD;AAED;;;;GAIG;AACH,qBAAa,aAAc,YAAW,QAAQ;IAChC,OAAO,CAAC,QAAQ,CAAC,EAAE;gBAAF,EAAE,EAAE,WAAW;IAEtC,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAalE,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAIjD"}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Manages pre-paid credit balances for users.
3
+ *
4
+ * Credits are stored in MongoDB (`userCredits` collection) and cached in-memory
5
+ * with a short TTL. Deductions use optimistic in-memory decrement + async DB write;
6
+ * grants are written directly to DB and then invalidate the cache.
7
+ */
8
+ export class CreditStore {
9
+ db;
10
+ cache = new Map();
11
+ ttlMs;
12
+ maxSize;
13
+ constructor(db, ttlMs = 3_600_000, // 1 hour
14
+ maxSize = 10_000) {
15
+ this.db = db;
16
+ this.ttlMs = ttlMs;
17
+ this.maxSize = maxSize;
18
+ }
19
+ /**
20
+ * Grant credits to a user (additive). Writes directly to DB; invalidates cache.
21
+ * Safe to call multiple times — amounts are accumulated.
22
+ */
23
+ async grant(userId, amountUsd) {
24
+ if (!Number.isFinite(amountUsd) || amountUsd <= 0) {
25
+ throw new Error(`[CreditStore] amountUsd must be finite positive, got ${String(amountUsd)}`);
26
+ }
27
+ const newBalance = await this.db.incrementCredit(userId, amountUsd);
28
+ this.setCache(userId, newBalance);
29
+ }
30
+ /**
31
+ * Get current credit balance (cached with TTL).
32
+ */
33
+ async getBalance(userId) {
34
+ const cached = this.cache.get(userId);
35
+ if (cached && Date.now() - cached.fetchedAt < this.ttlMs) {
36
+ return cached.balanceUsd;
37
+ }
38
+ const balance = await this.db.getCredit(userId);
39
+ this.setCache(userId, balance);
40
+ return balance;
41
+ }
42
+ /**
43
+ * Attempt to deduct costUsd from the user's credit balance.
44
+ * Returns true if deducted successfully, false if balance is insufficient.
45
+ * Uses optimistic in-memory decrement; DB write is async (fire-and-forget with logging).
46
+ */
47
+ async tryDeduct(userId, costUsd) {
48
+ const balance = await this.getBalance(userId);
49
+ if (balance < costUsd)
50
+ return false;
51
+ // Optimistic: update cache immediately to prevent concurrent over-deduction
52
+ const newBalance = Math.max(0, balance - costUsd);
53
+ this.setCache(userId, newBalance);
54
+ // Persist to DB asynchronously
55
+ this.db
56
+ .incrementCredit(userId, -costUsd)
57
+ .then((dbBalance) => {
58
+ // Reconcile: if DB says something different, trust DB
59
+ this.setCache(userId, Math.max(0, dbBalance));
60
+ })
61
+ .catch((err) => {
62
+ console.error('[CreditStore] Failed to persist deduction', { userId, costUsd }, err);
63
+ // Roll back optimistic decrement on failure
64
+ this.setCache(userId, balance);
65
+ });
66
+ return true;
67
+ }
68
+ /** Invalidate cached balance for a user (e.g. after external grant). */
69
+ invalidate(userId) {
70
+ this.cache.delete(userId);
71
+ }
72
+ // ---------------------------------------------------------------------------
73
+ // Private
74
+ // ---------------------------------------------------------------------------
75
+ setCache(userId, balanceUsd) {
76
+ // Simple LRU eviction: if at capacity and key is new, evict oldest entry
77
+ if (!this.cache.has(userId) && this.cache.size >= this.maxSize) {
78
+ const oldest = this.cache.keys().next().value;
79
+ if (oldest !== undefined)
80
+ this.cache.delete(oldest);
81
+ }
82
+ this.cache.set(userId, { balanceUsd, fetchedAt: Date.now() });
83
+ }
84
+ }
85
+ /**
86
+ * MongoDB-backed CreditDB implementation.
87
+ * Uses findOneAndUpdate-style atomic increment via a helper that performs
88
+ * a read-modify-write with the document's balanceUsd field.
89
+ */
90
+ export class MongoCreditDB {
91
+ db;
92
+ constructor(db) {
93
+ this.db = db;
94
+ }
95
+ async incrementCredit(userId, deltaUsd) {
96
+ const existing = await this.db.getDoc(userId);
97
+ const current = existing?.balanceUsd ?? 0;
98
+ const newBalance = Math.max(0, current + deltaUsd);
99
+ const now = Date.now();
100
+ await this.db.setDoc(userId, {
101
+ id: userId,
102
+ balanceUsd: newBalance,
103
+ updated: now,
104
+ });
105
+ return newBalance;
106
+ }
107
+ async getCredit(userId) {
108
+ const doc = await this.db.getDoc(userId);
109
+ return doc?.balanceUsd ?? 0;
110
+ }
111
+ }
112
+ //# sourceMappingURL=CreditStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CreditStore.js","sourceRoot":"","sources":["../../../src/server/billing/CreditStore.ts"],"names":[],"mappings":"AAsBA;;;;;;GAMG;AACH,MAAM,OAAO,WAAW;IAMH;IALF,KAAK,GAAG,IAAI,GAAG,EAAsB,CAAC;IACtC,KAAK,CAAS;IACd,OAAO,CAAS;IAEjC,YACmB,EAAY,EAC7B,KAAK,GAAG,SAAS,EAAE,SAAS;IAC5B,OAAO,GAAG,MAAM;QAFC,OAAE,GAAF,EAAE,CAAU;QAI7B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,KAAK,CAAC,MAAc,EAAE,SAAiB;QAC3C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;YAClD,MAAM,IAAI,KAAK,CACb,wDAAwD,MAAM,CAC5D,SAAS,CACV,EAAE,CACJ,CAAC;QACJ,CAAC;QACD,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,eAAe,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QACpE,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACpC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,UAAU,CAAC,MAAc;QAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACtC,IAAI,MAAM,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;YACzD,OAAO,MAAM,CAAC,UAAU,CAAC;QAC3B,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAChD,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC/B,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,SAAS,CAAC,MAAc,EAAE,OAAe;QAC7C,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QAC9C,IAAI,OAAO,GAAG,OAAO;YAAE,OAAO,KAAK,CAAC;QAEpC,4EAA4E;QAC5E,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC;QAClD,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QAElC,+BAA+B;QAC/B,IAAI,CAAC,EAAE;aACJ,eAAe,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC;aACjC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE;YAClB,sDAAsD;YACtD,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;QAChD,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;YACtB,OAAO,CAAC,KAAK,CACX,2CAA2C,EAC3C,EAAE,MAAM,EAAE,OAAO,EAAE,EACnB,GAAG,CACJ,CAAC;YACF,4CAA4C;YAC5C,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;QAEL,OAAO,IAAI,CAAC;IACd,CAAC;IAED,wEAAwE;IACxE,UAAU,CAAC,MAAc;QACvB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC5B,CAAC;IAED,8EAA8E;IAC9E,UAAU;IACV,8EAA8E;IAEtE,QAAQ,CAAC,MAAc,EAAE,UAAkB;QACjD,yEAAyE;QACzE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAC/D,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;YAC9C,IAAI,MAAM,KAAK,SAAS;gBAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACtD,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAChE,CAAC;CACF;AAaD;;;;GAIG;AACH,MAAM,OAAO,aAAa;IACK;IAA7B,YAA6B,EAAe;QAAf,OAAE,GAAF,EAAE,CAAa;IAAG,CAAC;IAEhD,KAAK,CAAC,eAAe,CAAC,MAAc,EAAE,QAAgB;QACpD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC9C,MAAM,OAAO,GAAG,QAAQ,EAAE,UAAU,IAAI,CAAC,CAAC;QAC1C,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC,CAAC;QACnD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE;YAC3B,EAAE,EAAE,MAAM;YACV,UAAU,EAAE,UAAU;YACtB,OAAO,EAAE,GAAG;SACb,CAAC,CAAC;QACH,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,MAAc;QAC5B,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACzC,OAAO,GAAG,EAAE,UAAU,IAAI,CAAC,CAAC;IAC9B,CAAC;CACF"}
@@ -0,0 +1,73 @@
1
+ import type { BillingLedger } from './BillingLedger.js';
2
+ import type { CreditStore } from './CreditStore.js';
3
+ import type { BillingConfig, ChargeParams, GlobalThresholdCallback, UserThresholdCallback } from './types.js';
4
+ import type { UserLimitCache } from './UserLimitCache.js';
5
+ /**
6
+ * Checks all billing limits and fires threshold callbacks.
7
+ *
8
+ * Global and provider hourly limits use a synchronous in-memory rolling
9
+ * accumulator — race-free within a single Node.js process.
10
+ *
11
+ * Per-user hourly/daily/weekly limits perform async DB queries via BillingLedger.
12
+ *
13
+ * Known limitations (documented):
14
+ * - Multi-server: each server's accumulator is independent; limits are eventually
15
+ * consistent up to the reconciliation interval.
16
+ * - TOCTOU for per-user async checks: concurrent charges for the same userId can
17
+ * both pass under very high concurrent load. Mitigable with per-userId mutex (v2).
18
+ */
19
+ export declare class LimitEnforcer {
20
+ private readonly ledger;
21
+ private readonly userLimits;
22
+ private readonly config;
23
+ private readonly credits;
24
+ private readonly accumulators;
25
+ private readonly firedThresholds;
26
+ private userThresholdCb;
27
+ private globalThresholdCb;
28
+ constructor(ledger: BillingLedger, userLimits: UserLimitCache, config: BillingConfig, credits?: CreditStore | null);
29
+ setUserThresholdCallback(fn: UserThresholdCallback): void;
30
+ setGlobalThresholdCallback(fn: GlobalThresholdCallback): void;
31
+ /**
32
+ * Load current-window spend from DB to warm the in-memory accumulators.
33
+ * Called by BillingGateway.start() before serving traffic.
34
+ */
35
+ init(): Promise<void>;
36
+ /**
37
+ * Check all applicable limits for a charge.
38
+ *
39
+ * Check order (observable — documented):
40
+ * 1. global-hourly
41
+ * 2. provider-hourly
42
+ * 3. user-hourly
43
+ * 4. user-daily
44
+ * 5. user-weekly
45
+ *
46
+ * Throws BillingLimitError on first violation.
47
+ * Throws BillingValidationError on invalid input.
48
+ */
49
+ check(params: ChargeParams): Promise<void>;
50
+ private addToAccumulator;
51
+ /** Remove the most recent entry that matches cost+ts (rollback of optimistic add). */
52
+ private removeFromAccumulator;
53
+ private pruneAccumulator;
54
+ private sumAccumulator;
55
+ private checkUserLimits;
56
+ /**
57
+ * If a CreditStore is configured and the user has sufficient balance, deduct and return.
58
+ * Otherwise throw the original limit error.
59
+ */
60
+ private tryCreditsOrThrow;
61
+ /**
62
+ * Fire the global/provider threshold callback if the charge crosses the threshold.
63
+ * Fires at most once per window per threshold ratio (deduplicated by firedThresholds map).
64
+ * Window reset is detected when the accumulator for that key becomes empty after pruning.
65
+ */
66
+ private maybeFireGlobalThreshold;
67
+ /**
68
+ * Fire the user threshold callback if the charge crosses a per-user window threshold.
69
+ * User threshold state is tracked per (userId, limitType) key.
70
+ */
71
+ private maybeFireUserThreshold;
72
+ }
73
+ //# sourceMappingURL=LimitEnforcer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LimitEnforcer.d.ts","sourceRoot":"","sources":["../../../src/server/billing/LimitEnforcer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EACZ,uBAAuB,EAEvB,qBAAqB,EACtB,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAW1D;;;;;;;;;;;;;GAaG;AACH,qBAAa,aAAa;IAQtB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAV1B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAyC;IAEtE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAkC;IAClE,OAAO,CAAC,eAAe,CAAsC;IAC7D,OAAO,CAAC,iBAAiB,CAAwC;gBAG9C,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,cAAc,EAC1B,MAAM,EAAE,aAAa,EACrB,OAAO,GAAE,WAAW,GAAG,IAAW;IAGrD,wBAAwB,CAAC,EAAE,EAAE,qBAAqB,GAAG,IAAI;IAIzD,0BAA0B,CAAC,EAAE,EAAE,uBAAuB,GAAG,IAAI;IAI7D;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB3B;;;;;;;;;;;;OAYG;IACG,KAAK,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAsFhD,OAAO,CAAC,gBAAgB;IAMxB,sFAAsF;IACtF,OAAO,CAAC,qBAAqB;IAW7B,OAAO,CAAC,gBAAgB;IAYxB,OAAO,CAAC,cAAc;YAUR,eAAe;IAuE7B;;;OAGG;YACW,iBAAiB;IAgB/B;;;;OAIG;IACH,OAAO,CAAC,wBAAwB;IAiChC;;;OAGG;IACH,OAAO,CAAC,sBAAsB;CAiC/B"}