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,162 @@
1
+ import { connect, RetentionPolicy, StringCodec, } from 'nats';
2
+ const codec = StringCodec();
3
+ let natsConnection = null;
4
+ let jetStreamClient = null;
5
+ // Active subscriptions tracked for leak detection
6
+ const activeSubscriptions = new Map();
7
+ let subIdCounter = 0;
8
+ const SUBSCRIPTION_LEAK_THRESHOLD = 20;
9
+ /**
10
+ * Connect to NATS. Called once at server startup.
11
+ * Development: connects to localhost:4222
12
+ * Production: uses NATS_URL env var (and NATS_CREDS for Synadia Cloud)
13
+ */
14
+ export async function connectNats(config) {
15
+ const url = config?.url ?? process.env['NATS_URL'] ?? 'nats://localhost:4222';
16
+ const connectOptions = { servers: url };
17
+ if (config?.creds ?? process.env['NATS_CREDS']) {
18
+ const { credsAuthenticator } = await import('nats');
19
+ const fs = await import('fs');
20
+ const credsPath = config?.creds ?? process.env['NATS_CREDS'];
21
+ const credsContent = fs.readFileSync(credsPath);
22
+ connectOptions.authenticator = credsAuthenticator(credsContent);
23
+ }
24
+ natsConnection = await connect(connectOptions);
25
+ console.log('[NATS] Connected', { url });
26
+ natsConnection
27
+ .closed()
28
+ .then(() => {
29
+ console.log('[NATS] Connection closed');
30
+ natsConnection = null;
31
+ jetStreamClient = null;
32
+ })
33
+ .catch((err) => {
34
+ console.error('[NATS] Connection closed with error', err);
35
+ natsConnection = null;
36
+ jetStreamClient = null;
37
+ });
38
+ return natsConnection;
39
+ }
40
+ /**
41
+ * Get the active NATS connection. Throws if not connected.
42
+ */
43
+ export function getNatsConnection() {
44
+ if (!natsConnection) {
45
+ throw new Error('[NATS] Not connected. Call connectNats() first.');
46
+ }
47
+ return natsConnection;
48
+ }
49
+ /**
50
+ * Publish a message to a NATS subject.
51
+ * @param subject - NATS subject (e.g. 'user.updates.abc123')
52
+ * @param payload - JSON-serializable payload
53
+ */
54
+ export function natsPublish(subject, payload) {
55
+ const conn = getNatsConnection();
56
+ conn.publish(subject, codec.encode(JSON.stringify(payload)));
57
+ }
58
+ /**
59
+ * Subscribe to a NATS subject.
60
+ * Returns an unsubscribe function — ALWAYS call it when done to prevent leaks.
61
+ *
62
+ * @example
63
+ * const unsub = await natsSubscribe('user.updates.*', (msg) => {
64
+ * console.log(msg.subject, msg.data);
65
+ * });
66
+ * // Later:
67
+ * unsub();
68
+ */
69
+ export async function natsSubscribe(subject, handler) {
70
+ const conn = getNatsConnection();
71
+ const sub = conn.subscribe(subject);
72
+ const subId = ++subIdCounter;
73
+ activeSubscriptions.set(String(subId), { subject, createdAt: new Date() });
74
+ // Check for subscription leaks
75
+ if (activeSubscriptions.size > SUBSCRIPTION_LEAK_THRESHOLD) {
76
+ const oldest = [...activeSubscriptions.entries()].sort((a, b) => a[1].createdAt.getTime() - b[1].createdAt.getTime())[0];
77
+ console.error('[NATS] Possible subscription leak detected', {
78
+ activeCount: activeSubscriptions.size,
79
+ threshold: SUBSCRIPTION_LEAK_THRESHOLD,
80
+ oldestSubject: oldest?.[1]?.subject,
81
+ oldestAge: oldest
82
+ ? `${Math.round((Date.now() - oldest[1].createdAt.getTime()) / 1000)}s`
83
+ : 'unknown',
84
+ fix: 'Ensure you call the unsubscribe() function returned by natsSubscribe()',
85
+ example: 'const unsub = await natsSubscribe(subject, handler); // later: unsub();',
86
+ });
87
+ }
88
+ // Process messages asynchronously
89
+ (async () => {
90
+ for await (const msg of sub) {
91
+ try {
92
+ const data = JSON.parse(codec.decode(msg.data));
93
+ await handler({ subject: msg.subject, data });
94
+ }
95
+ catch (err) {
96
+ console.error('[NATS] Message handler error', {
97
+ subject: msg.subject,
98
+ err,
99
+ });
100
+ }
101
+ }
102
+ })().catch((err) => {
103
+ console.error('[NATS] Subscription loop error', { subject, err });
104
+ });
105
+ return () => {
106
+ sub.unsubscribe();
107
+ activeSubscriptions.delete(String(subId));
108
+ };
109
+ }
110
+ /**
111
+ * Get the JetStream client for durable queues.
112
+ * JetStream must be enabled on the NATS server (pass -js flag).
113
+ */
114
+ export async function getJetStream() {
115
+ if (!jetStreamClient) {
116
+ const conn = getNatsConnection();
117
+ jetStreamClient = conn.jetstream();
118
+ }
119
+ return jetStreamClient;
120
+ }
121
+ /**
122
+ * Ensure a JetStream stream exists (idempotent).
123
+ * Creates the stream if it doesn't exist; updates if config differs.
124
+ */
125
+ export async function ensureStream(config) {
126
+ const conn = getNatsConnection();
127
+ const jsm = await conn.jetstreamManager();
128
+ try {
129
+ await jsm.streams.info(config.name);
130
+ // Stream exists, update subjects (retention policy cannot be changed after creation)
131
+ await jsm.streams.update(config.name, {
132
+ subjects: config.subjects,
133
+ });
134
+ }
135
+ catch (err) {
136
+ // Only create if stream doesn't exist; re-throw other errors
137
+ const isNotFound = err instanceof Error &&
138
+ (err.message.includes('stream not found') || err.message.includes('404'));
139
+ if (!isNotFound) {
140
+ throw err;
141
+ }
142
+ // Stream doesn't exist, create it
143
+ await jsm.streams.add({
144
+ name: config.name,
145
+ subjects: config.subjects,
146
+ retention: config.retentionPolicy ?? RetentionPolicy.Limits,
147
+ });
148
+ console.log('[NATS] Stream created', { name: config.name });
149
+ }
150
+ }
151
+ /**
152
+ * Gracefully close the NATS connection.
153
+ * Call during server shutdown.
154
+ */
155
+ export async function closeNats() {
156
+ if (natsConnection) {
157
+ await natsConnection.close();
158
+ natsConnection = null;
159
+ jetStreamClient = null;
160
+ }
161
+ }
162
+ //# sourceMappingURL=Nats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Nats.js","sourceRoot":"","sources":["../../src/server/Nats.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { DBObject } from '../shared/DB.js';
2
+ export type NatsDocMessage<T = DBObject> = {
3
+ type: 'update';
4
+ item: T;
5
+ } | {
6
+ type: 'delete';
7
+ id: string;
8
+ };
9
+ /**
10
+ * Subscribe to changes for a specific document.
11
+ * Subject format: db.{collection}.{escapeNatsToken(id)}
12
+ * Returns an unsubscribe function (synchronous).
13
+ *
14
+ * Do NOT use natsSubscribe() from Nats.ts — it is async. Call conn.subscribe() directly.
15
+ */
16
+ export declare function subscribeDoc(collection: string, id: string, callback: (msg: NatsDocMessage) => void): () => void;
17
+ /**
18
+ * Subscribe to all doc-level changes in a collection.
19
+ * Subject: db.{collection}.> (wildcard — matches all doc-level subjects).
20
+ * The bare db.{collection} collection-level events are intentionally not subscribed to;
21
+ * DocumentNotifier always publishes both, so doc-level events alone are sufficient.
22
+ * Returns an unsubscribe function (synchronous).
23
+ */
24
+ export declare function subscribeCollection(collection: string, callback: (msg: NatsDocMessage) => void): () => void;
25
+ export declare function escapeNatsToken(token: string): string;
26
+ //# sourceMappingURL=NatsStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NatsStore.d.ts","sourceRoot":"","sources":["../../src/server/NatsStore.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAsBhD,MAAM,MAAM,cAAc,CAAC,CAAC,GAAG,QAAQ,IACnC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,CAAC,CAAA;CAAE,GAC3B;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnC;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,GACtC,MAAM,IAAI,CAuBZ;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,GACtC,MAAM,IAAI,CAuBZ;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMrD"}
@@ -0,0 +1,86 @@
1
+ import { StringCodec } from 'nats';
2
+ import { getNatsConnection } from './Nats.js';
3
+ const sc = StringCodec();
4
+ // Subscription leak detection — separate from Nats.ts's tracker because
5
+ // NatsStore calls conn.subscribe() directly (not natsSubscribe()).
6
+ // Threshold is 100 (vs Nats.ts's 20) because each tracked doc per connected
7
+ // socket opens one subscription; steady-state with active users easily reaches 50+.
8
+ let activeCount = 0;
9
+ const LEAK_THRESHOLD = 100;
10
+ function checkLeak(subject) {
11
+ activeCount++;
12
+ if (activeCount > LEAK_THRESHOLD) {
13
+ console.warn('[NatsStore] Subscription leak detected', {
14
+ activeCount,
15
+ subject,
16
+ });
17
+ }
18
+ }
19
+ /**
20
+ * Subscribe to changes for a specific document.
21
+ * Subject format: db.{collection}.{escapeNatsToken(id)}
22
+ * Returns an unsubscribe function (synchronous).
23
+ *
24
+ * Do NOT use natsSubscribe() from Nats.ts — it is async. Call conn.subscribe() directly.
25
+ */
26
+ export function subscribeDoc(collection, id, callback) {
27
+ const subject = `db.${collection}.${escapeNatsToken(id)}`;
28
+ const conn = getNatsConnection();
29
+ const sub = conn.subscribe(subject);
30
+ checkLeak(subject);
31
+ (async () => {
32
+ for await (const msg of sub) {
33
+ try {
34
+ const parsed = JSON.parse(sc.decode(msg.data));
35
+ callback(parsed);
36
+ }
37
+ catch (err) {
38
+ console.error('[NatsStore] Failed to parse message', { subject, err });
39
+ }
40
+ }
41
+ })().catch((err) => {
42
+ console.error('[NatsStore] Subscription loop error', { subject, err });
43
+ });
44
+ return () => {
45
+ sub.unsubscribe();
46
+ activeCount--;
47
+ };
48
+ }
49
+ /**
50
+ * Subscribe to all doc-level changes in a collection.
51
+ * Subject: db.{collection}.> (wildcard — matches all doc-level subjects).
52
+ * The bare db.{collection} collection-level events are intentionally not subscribed to;
53
+ * DocumentNotifier always publishes both, so doc-level events alone are sufficient.
54
+ * Returns an unsubscribe function (synchronous).
55
+ */
56
+ export function subscribeCollection(collection, callback) {
57
+ const subject = `db.${collection}.>`;
58
+ const conn = getNatsConnection();
59
+ const sub = conn.subscribe(subject);
60
+ checkLeak(subject);
61
+ (async () => {
62
+ for await (const msg of sub) {
63
+ try {
64
+ const parsed = JSON.parse(sc.decode(msg.data));
65
+ callback(parsed);
66
+ }
67
+ catch (err) {
68
+ console.error('[NatsStore] Failed to parse message', { subject, err });
69
+ }
70
+ }
71
+ })().catch((err) => {
72
+ console.error('[NatsStore] Subscription loop error', { subject, err });
73
+ });
74
+ return () => {
75
+ sub.unsubscribe();
76
+ activeCount--;
77
+ };
78
+ }
79
+ export function escapeNatsToken(token) {
80
+ return token
81
+ .replace(/\./g, '_DOT_')
82
+ .replace(/\+/g, '_PLUS_')
83
+ .replace(/\*/g, '_STAR_')
84
+ .replace(/>/g, '_GT_');
85
+ }
86
+ //# sourceMappingURL=NatsStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NatsStore.js","sourceRoot":"","sources":["../../src/server/NatsStore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import type { WebSocket } from 'ws';
2
+ export interface PushNotification {
3
+ title: string;
4
+ body: string;
5
+ uri?: string;
6
+ imageUrl?: string;
7
+ data?: Record<string, string>;
8
+ }
9
+ export interface PushToken {
10
+ userId: string;
11
+ token: string;
12
+ platform: 'web' | 'ios' | 'android';
13
+ updatedAt: Date;
14
+ }
15
+ /**
16
+ * Register a WebSocket connection for push notifications.
17
+ * Called when a user authenticates a WebSocket session.
18
+ * Returns an unregister function to call when connection closes.
19
+ */
20
+ export declare function registerPushConnection(userId: string, ws: WebSocket): Promise<() => void>;
21
+ /**
22
+ * Send a push notification to a user.
23
+ * Delivers via WebSocket (cross-server via Redis pub/sub).
24
+ * Also sends via FCM if token is available and FCM is configured.
25
+ */
26
+ export declare function sendPush(userId: string, notification: PushNotification): Promise<void>;
27
+ /**
28
+ * Send an FCM push notification.
29
+ * Only works if Firebase is configured via env vars:
30
+ * FIREBASE_PROJECT_ID, FIREBASE_PRIVATE_KEY, FIREBASE_CLIENT_EMAIL
31
+ */
32
+ export declare function sendFcmPush(fcmToken: string, notification: PushNotification): Promise<void>;
33
+ //# sourceMappingURL=PushNotification.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PushNotification.d.ts","sourceRoot":"","sources":["../../src/server/PushNotification.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAGpC,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,KAAK,GAAG,KAAK,GAAG,SAAS,CAAC;IACpC,SAAS,EAAE,IAAI,CAAC;CACjB;AAUD;;;;GAIG;AACH,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,MAAM,EACd,EAAE,EAAE,SAAS,GACZ,OAAO,CAAC,MAAM,IAAI,CAAC,CAkCrB;AA4BD;;;;GAIG;AACH,wBAAsB,QAAQ,CAC5B,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,gBAAgB,GAC7B,OAAO,CAAC,IAAI,CAAC,CAKf;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,gBAAgB,GAC7B,OAAO,CAAC,IAAI,CAAC,CAoDf"}
@@ -0,0 +1,131 @@
1
+ import { redisPublish, redisSubscribe } from './Redis.js';
2
+ const PUSH_CHANNEL_PREFIX = 'push:';
3
+ // Map of userId → Set of local WebSocket connections
4
+ const localConnections = new Map();
5
+ // Map of userId → Redis unsubscribe function (one subscription per userId)
6
+ const redisUnsubscribers = new Map();
7
+ /**
8
+ * Register a WebSocket connection for push notifications.
9
+ * Called when a user authenticates a WebSocket session.
10
+ * Returns an unregister function to call when connection closes.
11
+ */
12
+ export async function registerPushConnection(userId, ws) {
13
+ if (!localConnections.has(userId)) {
14
+ localConnections.set(userId, new Set());
15
+ }
16
+ localConnections.get(userId).add(ws);
17
+ // Subscribe to Redis if this is the first connection for this user.
18
+ // Set a no-op placeholder BEFORE the await so concurrent calls for the same
19
+ // userId skip this branch and don't create duplicate Redis subscriptions.
20
+ if (!redisUnsubscribers.has(userId)) {
21
+ redisUnsubscribers.set(userId, () => { }); // placeholder — prevents race
22
+ const unsub = await redisSubscribe(`${PUSH_CHANNEL_PREFIX}${userId}`, (message) => {
23
+ deliverToLocalConnections(userId, message);
24
+ });
25
+ redisUnsubscribers.set(userId, unsub); // replace placeholder with real unsub
26
+ }
27
+ return () => {
28
+ const connections = localConnections.get(userId);
29
+ if (connections) {
30
+ connections.delete(ws);
31
+ if (connections.size === 0) {
32
+ localConnections.delete(userId);
33
+ const unsub = redisUnsubscribers.get(userId);
34
+ if (unsub) {
35
+ unsub();
36
+ redisUnsubscribers.delete(userId);
37
+ }
38
+ }
39
+ }
40
+ };
41
+ }
42
+ function deliverToLocalConnections(userId, message) {
43
+ const connections = localConnections.get(userId);
44
+ if (!connections)
45
+ return;
46
+ let notification;
47
+ try {
48
+ notification = JSON.parse(message);
49
+ }
50
+ catch (err) {
51
+ console.error('[Push] Failed to parse notification message', {
52
+ userId,
53
+ err,
54
+ });
55
+ return;
56
+ }
57
+ for (const ws of connections) {
58
+ if (ws.readyState === 1 /* OPEN */) {
59
+ try {
60
+ ws.send(JSON.stringify({ type: 'pushNotification', data: notification }));
61
+ }
62
+ catch (err) {
63
+ console.error('[Push] WebSocket send error', { userId, err });
64
+ }
65
+ }
66
+ }
67
+ }
68
+ /**
69
+ * Send a push notification to a user.
70
+ * Delivers via WebSocket (cross-server via Redis pub/sub).
71
+ * Also sends via FCM if token is available and FCM is configured.
72
+ */
73
+ export async function sendPush(userId, notification) {
74
+ const message = JSON.stringify(notification);
75
+ // Publish to Redis → all servers with connections for this user receive it
76
+ await redisPublish(`${PUSH_CHANNEL_PREFIX}${userId}`, message);
77
+ }
78
+ /**
79
+ * Send an FCM push notification.
80
+ * Only works if Firebase is configured via env vars:
81
+ * FIREBASE_PROJECT_ID, FIREBASE_PRIVATE_KEY, FIREBASE_CLIENT_EMAIL
82
+ */
83
+ export async function sendFcmPush(fcmToken, notification) {
84
+ const projectId = process.env['FIREBASE_PROJECT_ID'];
85
+ const privateKey = process.env['FIREBASE_PRIVATE_KEY'];
86
+ const clientEmail = process.env['FIREBASE_CLIENT_EMAIL'];
87
+ if (!projectId || !privateKey || !clientEmail) {
88
+ console.error('[Push] FCM not configured - missing FIREBASE_* env vars');
89
+ return;
90
+ }
91
+ try {
92
+ // Dynamic import via Function to avoid TS static resolution of optional dep
93
+ // eslint-disable-next-line @typescript-eslint/no-implied-eval
94
+ const importFn = new Function('m', 'return import(m)');
95
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
96
+ const admin = (await importFn('firebase-admin'));
97
+ if (!admin.apps.length) {
98
+ admin.initializeApp({
99
+ credential: admin.credential.cert({
100
+ projectId,
101
+ privateKey: privateKey.replace(/\\n/g, '\n'),
102
+ clientEmail,
103
+ }),
104
+ });
105
+ }
106
+ await admin.messaging().send({
107
+ token: fcmToken,
108
+ notification: {
109
+ title: notification.title,
110
+ body: notification.body,
111
+ imageUrl: notification.imageUrl,
112
+ },
113
+ webpush: notification.uri
114
+ ? {
115
+ fcmOptions: { link: notification.uri },
116
+ }
117
+ : undefined,
118
+ apns: notification.uri
119
+ ? {
120
+ payload: { aps: { sound: 'default' } },
121
+ fcmOptions: { imageUrl: notification.imageUrl },
122
+ }
123
+ : undefined,
124
+ data: notification.data,
125
+ });
126
+ }
127
+ catch (err) {
128
+ console.error('[Push] FCM send error', { err });
129
+ }
130
+ }
131
+ //# sourceMappingURL=PushNotification.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PushNotification.js","sourceRoot":"","sources":["../../src/server/PushNotification.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ export interface RateLimitConfig {
2
+ windowSeconds?: number;
3
+ maxPerWindow?: number;
4
+ maxQueueDepth?: number;
5
+ maxWaitMs?: number;
6
+ }
7
+ export interface UsageRecord {
8
+ userId: string;
9
+ operation: string;
10
+ used: number;
11
+ limit: number;
12
+ windowStart: Date;
13
+ queued: number;
14
+ }
15
+ export interface RateLimiter {
16
+ check(userId: string, operation: string, estimatedCost: number): Promise<void>;
17
+ charge(userId: string, operation: string, actualCost: number): Promise<void>;
18
+ getUsage(userId: string, operation: string): Promise<UsageRecord>;
19
+ }
20
+ export declare class RateLimitError extends Error {
21
+ readonly userId: string;
22
+ readonly operation: string;
23
+ readonly used: number;
24
+ readonly limit: number;
25
+ constructor(userId: string, operation: string, used: number, limit: number);
26
+ }
27
+ export declare function createRateLimiter(config?: RateLimitConfig): RateLimiter;
28
+ //# sourceMappingURL=RateLimit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RateLimit.d.ts","sourceRoot":"","sources":["../../src/server/RateLimit.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAE9B,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,IAAI,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAK1B,KAAK,CACH,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC,CAAC;IAGjB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAG7E,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CACnE;AAED,qBAAa,cAAe,SAAQ,KAAK;aAErB,MAAM,EAAE,MAAM;aACd,SAAS,EAAE,MAAM;aACjB,IAAI,EAAE,MAAM;aACZ,KAAK,EAAE,MAAM;gBAHb,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM;CAKhC;AAED,wBAAgB,iBAAiB,CAAC,MAAM,GAAE,eAAoB,GAAG,WAAW,CAgH3E"}
@@ -0,0 +1,101 @@
1
+ export class RateLimitError extends Error {
2
+ userId;
3
+ operation;
4
+ used;
5
+ limit;
6
+ constructor(userId, operation, used, limit) {
7
+ super(`[RateLimit] Rate limit exceeded for operation '${operation}'`);
8
+ this.userId = userId;
9
+ this.operation = operation;
10
+ this.used = used;
11
+ this.limit = limit;
12
+ this.name = 'RateLimitError';
13
+ }
14
+ }
15
+ export function createRateLimiter(config = {}) {
16
+ const { windowSeconds = 3600, maxPerWindow = 1.0, maxQueueDepth = 100, maxWaitMs = 300_000, } = config;
17
+ const usages = new Map();
18
+ function getKey(userId, operation) {
19
+ return `${userId}:${operation}`;
20
+ }
21
+ function getUsageEntry(key) {
22
+ let entry = usages.get(key);
23
+ if (!entry) {
24
+ entry = { used: 0, windowStart: new Date(), queue: [] };
25
+ usages.set(key, entry);
26
+ }
27
+ // Reset window if expired
28
+ const age = (Date.now() - entry.windowStart.getTime()) / 1000;
29
+ if (age >= windowSeconds) {
30
+ entry.used = 0;
31
+ entry.windowStart = new Date();
32
+ }
33
+ return entry;
34
+ }
35
+ function drainQueue(entry) {
36
+ while (entry.queue.length > 0) {
37
+ const next = entry.queue[0];
38
+ if (entry.used + next.cost <= maxPerWindow) {
39
+ entry.queue.shift();
40
+ next.resolve();
41
+ }
42
+ else {
43
+ break;
44
+ }
45
+ }
46
+ }
47
+ return {
48
+ async check(userId, operation, estimatedCost) {
49
+ const key = getKey(userId, operation);
50
+ const entry = getUsageEntry(key);
51
+ if (entry.used + estimatedCost <= maxPerWindow) {
52
+ // Within limit — proceed immediately
53
+ return;
54
+ }
55
+ // A single request that exceeds the entire window limit can never be served.
56
+ // Queuing it would block for maxWaitMs with no possibility of resolution.
57
+ if (estimatedCost > maxPerWindow) {
58
+ throw new RateLimitError(userId, operation, entry.used, maxPerWindow);
59
+ }
60
+ // Over limit — queue if there's room
61
+ if (entry.queue.length >= maxQueueDepth) {
62
+ throw new RateLimitError(userId, operation, entry.used, maxPerWindow);
63
+ }
64
+ await new Promise((resolve, reject) => {
65
+ const timer = setTimeout(() => {
66
+ const idx = entry.queue.findIndex((q) => q.resolve === resolve);
67
+ if (idx >= 0)
68
+ entry.queue.splice(idx, 1);
69
+ reject(new RateLimitError(userId, operation, entry.used, maxPerWindow));
70
+ }, maxWaitMs);
71
+ entry.queue.push({
72
+ cost: estimatedCost,
73
+ resolve: () => {
74
+ clearTimeout(timer);
75
+ resolve();
76
+ },
77
+ reject,
78
+ });
79
+ });
80
+ },
81
+ async charge(userId, operation, actualCost) {
82
+ const key = getKey(userId, operation);
83
+ const entry = getUsageEntry(key);
84
+ entry.used += actualCost;
85
+ drainQueue(entry);
86
+ },
87
+ async getUsage(userId, operation) {
88
+ const key = getKey(userId, operation);
89
+ const entry = getUsageEntry(key);
90
+ return {
91
+ userId,
92
+ operation,
93
+ used: entry.used,
94
+ limit: maxPerWindow,
95
+ windowStart: entry.windowStart,
96
+ queued: entry.queue.length,
97
+ };
98
+ },
99
+ };
100
+ }
101
+ //# sourceMappingURL=RateLimit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RateLimit.js","sourceRoot":"","sources":["../../src/server/RateLimit.ts"],"names":[],"mappings":"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"}