ugly-app 0.1.463 → 0.1.464
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.
- package/README.md +445 -878
- package/dist/cli/authCommands.d.ts +9 -0
- package/dist/cli/authCommands.d.ts.map +1 -0
- package/dist/cli/authCommands.js +86 -0
- package/dist/cli/authCommands.js.map +1 -0
- package/dist/cli/authStore.d.ts +13 -0
- package/dist/cli/authStore.d.ts.map +1 -0
- package/dist/cli/authStore.js +154 -0
- package/dist/cli/authStore.js.map +1 -0
- package/dist/cli/bootstrapMigration.d.ts +18 -0
- package/dist/cli/bootstrapMigration.d.ts.map +1 -0
- package/dist/cli/bootstrapMigration.js +44 -0
- package/dist/cli/bootstrapMigration.js.map +1 -0
- package/dist/cli/build.d.ts +2 -0
- package/dist/cli/build.d.ts.map +1 -0
- package/dist/cli/build.js +76 -0
- package/dist/cli/build.js.map +1 -0
- package/dist/cli/cloudCleanup.d.ts +4 -0
- package/dist/cli/cloudCleanup.d.ts.map +1 -0
- package/dist/cli/cloudCleanup.js +92 -0
- package/dist/cli/cloudCleanup.js.map +1 -0
- package/dist/cli/configure.d.ts +2 -0
- package/dist/cli/configure.d.ts.map +1 -0
- package/dist/cli/configure.js +52 -0
- package/dist/cli/configure.js.map +1 -0
- package/dist/cli/deployClient.d.ts +8 -0
- package/dist/cli/deployClient.d.ts.map +1 -0
- package/dist/cli/deployClient.js +71 -0
- package/dist/cli/deployClient.js.map +1 -0
- package/dist/cli/deployDestroy.d.ts +2 -0
- package/dist/cli/deployDestroy.d.ts.map +1 -0
- package/dist/cli/deployDestroy.js +30 -0
- package/dist/cli/deployDestroy.js.map +1 -0
- package/dist/cli/deployDomain.d.ts +2 -0
- package/dist/cli/deployDomain.d.ts.map +1 -0
- package/dist/cli/deployDomain.js +32 -0
- package/dist/cli/deployDomain.js.map +1 -0
- package/dist/cli/deployProd.d.ts +2 -0
- package/dist/cli/deployProd.d.ts.map +1 -0
- package/dist/cli/deployProd.js +9 -0
- package/dist/cli/deployProd.js.map +1 -0
- package/dist/cli/deployRemote.d.ts +6 -0
- package/dist/cli/deployRemote.d.ts.map +1 -0
- package/dist/cli/deployRemote.js +177 -0
- package/dist/cli/deployRemote.js.map +1 -0
- package/dist/cli/deployTar.d.ts +3 -0
- package/dist/cli/deployTar.d.ts.map +1 -0
- package/dist/cli/deployTar.js +24 -0
- package/dist/cli/deployTar.js.map +1 -0
- package/dist/cli/deployVersions.d.ts +3 -0
- package/dist/cli/deployVersions.d.ts.map +1 -0
- package/dist/cli/deployVersions.js +37 -0
- package/dist/cli/deployVersions.js.map +1 -0
- package/dist/cli/dev.d.ts +5 -0
- package/dist/cli/dev.d.ts.map +1 -0
- package/dist/cli/dev.js +213 -0
- package/dist/cli/dev.js.map +1 -0
- package/dist/cli/devTunnel.d.ts +37 -0
- package/dist/cli/devTunnel.d.ts.map +1 -0
- package/dist/cli/devTunnel.js +470 -0
- package/dist/cli/devTunnel.js.map +1 -0
- package/dist/cli/doctor.d.ts +22 -0
- package/dist/cli/doctor.d.ts.map +1 -0
- package/dist/cli/doctor.js +244 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/ensureInfra.d.ts +9 -0
- package/dist/cli/ensureInfra.d.ts.map +1 -0
- package/dist/cli/ensureInfra.js +112 -0
- package/dist/cli/ensureInfra.js.map +1 -0
- package/dist/cli/exportCollections.d.ts +18 -0
- package/dist/cli/exportCollections.d.ts.map +1 -0
- package/dist/cli/exportCollections.js +71 -0
- package/dist/cli/exportCollections.js.map +1 -0
- package/dist/cli/feedbackResolve.d.ts +7 -0
- package/dist/cli/feedbackResolve.d.ts.map +1 -0
- package/dist/cli/feedbackResolve.js +38 -0
- package/dist/cli/feedbackResolve.js.map +1 -0
- package/dist/cli/feedbackSubmit.d.ts +13 -0
- package/dist/cli/feedbackSubmit.d.ts.map +1 -0
- package/dist/cli/feedbackSubmit.js +88 -0
- package/dist/cli/feedbackSubmit.js.map +1 -0
- package/dist/cli/imageGen.d.ts +6 -0
- package/dist/cli/imageGen.d.ts.map +1 -0
- package/dist/cli/imageGen.js +77 -0
- package/dist/cli/imageGen.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +609 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/logQuery.d.ts +12 -0
- package/dist/cli/logQuery.d.ts.map +1 -0
- package/dist/cli/logQuery.js +176 -0
- package/dist/cli/logQuery.js.map +1 -0
- package/dist/cli/migrate.d.ts +4 -0
- package/dist/cli/migrate.d.ts.map +1 -0
- package/dist/cli/migrate.js +92 -0
- package/dist/cli/migrate.js.map +1 -0
- package/dist/cli/probeAuth.d.ts +44 -0
- package/dist/cli/probeAuth.d.ts.map +1 -0
- package/dist/cli/probeAuth.js +250 -0
- package/dist/cli/probeAuth.js.map +1 -0
- package/dist/cli/publishAssets.d.ts +6 -0
- package/dist/cli/publishAssets.d.ts.map +1 -0
- package/dist/cli/publishAssets.js +87 -0
- package/dist/cli/publishAssets.js.map +1 -0
- package/dist/cli/purgeAssets.d.ts +2 -0
- package/dist/cli/purgeAssets.d.ts.map +1 -0
- package/dist/cli/purgeAssets.js +36 -0
- package/dist/cli/purgeAssets.js.map +1 -0
- package/dist/cli/resolveBin.d.ts +65 -0
- package/dist/cli/resolveBin.d.ts.map +1 -0
- package/dist/cli/resolveBin.js +187 -0
- package/dist/cli/resolveBin.js.map +1 -0
- package/dist/cli/scaffold.d.ts +2 -0
- package/dist/cli/scaffold.d.ts.map +1 -0
- package/dist/cli/scaffold.js +76 -0
- package/dist/cli/scaffold.js.map +1 -0
- package/dist/cli/schemaGen.d.ts +7 -0
- package/dist/cli/schemaGen.d.ts.map +1 -0
- package/dist/cli/schemaGen.js +213 -0
- package/dist/cli/schemaGen.js.map +1 -0
- package/dist/cli/schemaStatus.d.ts +2 -0
- package/dist/cli/schemaStatus.d.ts.map +1 -0
- package/dist/cli/schemaStatus.js +32 -0
- package/dist/cli/schemaStatus.js.map +1 -0
- package/dist/cli/serverLogQueryApi.d.ts +12 -0
- package/dist/cli/serverLogQueryApi.d.ts.map +1 -0
- package/dist/cli/serverLogQueryApi.js +169 -0
- package/dist/cli/serverLogQueryApi.js.map +1 -0
- package/dist/cli/sidecar.d.ts +21 -0
- package/dist/cli/sidecar.d.ts.map +1 -0
- package/dist/cli/sidecar.js +294 -0
- package/dist/cli/sidecar.js.map +1 -0
- package/dist/cli/sidecarHealth.d.ts +13 -0
- package/dist/cli/sidecarHealth.d.ts.map +1 -0
- package/dist/cli/sidecarHealth.js +42 -0
- package/dist/cli/sidecarHealth.js.map +1 -0
- package/dist/cli/sidecarProtocol.d.ts +41 -0
- package/dist/cli/sidecarProtocol.d.ts.map +1 -0
- package/dist/cli/sidecarProtocol.js +61 -0
- package/dist/cli/sidecarProtocol.js.map +1 -0
- package/dist/cli/storageClient.d.ts +3 -0
- package/dist/cli/storageClient.d.ts.map +1 -0
- package/dist/cli/storageClient.js +11 -0
- package/dist/cli/storageClient.js.map +1 -0
- package/dist/cli/textGen.d.ts +8 -0
- package/dist/cli/textGen.d.ts.map +1 -0
- package/dist/cli/textGen.js +51 -0
- package/dist/cli/textGen.js.map +1 -0
- package/dist/cli/uglyBotAuth.d.ts +18 -0
- package/dist/cli/uglyBotAuth.d.ts.map +1 -0
- package/dist/cli/uglyBotAuth.js +50 -0
- package/dist/cli/uglyBotAuth.js.map +1 -0
- package/dist/cli/uglyBotLogin.d.ts +12 -0
- package/dist/cli/uglyBotLogin.d.ts.map +1 -0
- package/dist/cli/uglyBotLogin.js +83 -0
- package/dist/cli/uglyBotLogin.js.map +1 -0
- package/dist/cli/uglyBotSetup.d.ts +6 -0
- package/dist/cli/uglyBotSetup.d.ts.map +1 -0
- package/dist/cli/uglyBotSetup.js +36 -0
- package/dist/cli/uglyBotSetup.js.map +1 -0
- package/dist/cli/uglyappConfig.d.ts +34 -0
- package/dist/cli/uglyappConfig.d.ts.map +1 -0
- package/dist/cli/uglyappConfig.js +174 -0
- package/dist/cli/uglyappConfig.js.map +1 -0
- package/dist/cli/uglyappConfig.test.d.ts +2 -0
- package/dist/cli/uglyappConfig.test.d.ts.map +1 -0
- package/dist/cli/uglyappConfig.test.js +39 -0
- package/dist/cli/uglyappConfig.test.js.map +1 -0
- package/dist/cli/upgrade.d.ts +2 -0
- package/dist/cli/upgrade.d.ts.map +1 -0
- package/dist/cli/upgrade.js +132 -0
- package/dist/cli/upgrade.js.map +1 -0
- package/dist/cli/url.d.ts +2 -0
- package/dist/cli/url.d.ts.map +1 -0
- package/dist/cli/url.js +7 -0
- package/dist/cli/url.js.map +1 -0
- package/dist/cli/version.d.ts +2 -0
- package/dist/cli/version.d.ts.map +1 -0
- package/dist/cli/version.js +3 -0
- package/dist/cli/version.js.map +1 -0
- package/dist/cli/workerGen.d.ts +33 -0
- package/dist/cli/workerGen.d.ts.map +1 -0
- package/dist/cli/workerGen.js +152 -0
- package/dist/cli/workerGen.js.map +1 -0
- package/dist/client/AppApi.d.ts +17 -0
- package/dist/client/AppApi.d.ts.map +1 -0
- package/dist/client/AppApi.js +44 -0
- package/dist/client/AppApi.js.map +1 -0
- package/dist/client/AppProvider.d.ts +36 -0
- package/dist/client/AppProvider.d.ts.map +1 -0
- package/dist/client/AppProvider.js +158 -0
- package/dist/client/AppProvider.js.map +1 -0
- package/dist/client/ErrorLog.d.ts +15 -0
- package/dist/client/ErrorLog.d.ts.map +1 -0
- package/dist/client/ErrorLog.js +35 -0
- package/dist/client/ErrorLog.js.map +1 -0
- package/dist/client/FeedbackContext.d.ts +7 -0
- package/dist/client/FeedbackContext.d.ts.map +1 -0
- package/dist/client/FeedbackContext.js +15 -0
- package/dist/client/FeedbackContext.js.map +1 -0
- package/dist/client/Logger.d.ts +12 -0
- package/dist/client/Logger.d.ts.map +1 -0
- package/dist/client/Logger.js +302 -0
- package/dist/client/Logger.js.map +1 -0
- package/dist/client/LoginPopup.d.ts +8 -0
- package/dist/client/LoginPopup.d.ts.map +1 -0
- package/dist/client/LoginPopup.js +57 -0
- package/dist/client/LoginPopup.js.map +1 -0
- package/dist/client/Router.d.ts +92 -0
- package/dist/client/Router.d.ts.map +1 -0
- package/dist/client/Router.js +392 -0
- package/dist/client/Router.js.map +1 -0
- package/dist/client/Screenshot.d.ts +60 -0
- package/dist/client/Screenshot.d.ts.map +1 -0
- package/dist/client/Screenshot.js +174 -0
- package/dist/client/Screenshot.js.map +1 -0
- package/dist/client/StringsProvider.d.ts +46 -0
- package/dist/client/StringsProvider.d.ts.map +1 -0
- package/dist/client/StringsProvider.js +140 -0
- package/dist/client/StringsProvider.js.map +1 -0
- package/dist/client/ViewFlipper.d.ts +16 -0
- package/dist/client/ViewFlipper.d.ts.map +1 -0
- package/dist/client/ViewFlipper.js +173 -0
- package/dist/client/ViewFlipper.js.map +1 -0
- package/dist/client/animation/Animated.d.ts +19 -0
- package/dist/client/animation/Animated.d.ts.map +1 -0
- package/dist/client/animation/Animated.js +115 -0
- package/dist/client/animation/Animated.js.map +1 -0
- package/dist/client/animation/animatedValue.d.ts +52 -0
- package/dist/client/animation/animatedValue.d.ts.map +1 -0
- package/dist/client/animation/animatedValue.js +151 -0
- package/dist/client/animation/animatedValue.js.map +1 -0
- package/dist/client/animation/useAnimatedTransition.d.ts +92 -0
- package/dist/client/animation/useAnimatedTransition.d.ts.map +1 -0
- package/dist/client/animation/useAnimatedTransition.js +235 -0
- package/dist/client/animation/useAnimatedTransition.js.map +1 -0
- package/dist/client/animation/useScrollAnimation.d.ts +32 -0
- package/dist/client/animation/useScrollAnimation.d.ts.map +1 -0
- package/dist/client/animation/useScrollAnimation.js +82 -0
- package/dist/client/animation/useScrollAnimation.js.map +1 -0
- package/dist/client/animations/FadeIn.d.ts +6 -0
- package/dist/client/animations/FadeIn.d.ts.map +1 -0
- package/dist/client/animations/FadeIn.js +24 -0
- package/dist/client/animations/FadeIn.js.map +1 -0
- package/dist/client/animations/SlideFromBottom.d.ts +6 -0
- package/dist/client/animations/SlideFromBottom.d.ts.map +1 -0
- package/dist/client/animations/SlideFromBottom.js +24 -0
- package/dist/client/animations/SlideFromBottom.js.map +1 -0
- package/dist/client/animations/SlideFromRight.d.ts +6 -0
- package/dist/client/animations/SlideFromRight.d.ts.map +1 -0
- package/dist/client/animations/SlideFromRight.js +24 -0
- package/dist/client/animations/SlideFromRight.js.map +1 -0
- package/dist/client/audio/AudioPlayer.d.ts +11 -0
- package/dist/client/audio/AudioPlayer.d.ts.map +1 -0
- package/dist/client/audio/AudioPlayer.js +93 -0
- package/dist/client/audio/AudioPlayer.js.map +1 -0
- package/dist/client/audio/AudioRecorder.d.ts +11 -0
- package/dist/client/audio/AudioRecorder.d.ts.map +1 -0
- package/dist/client/audio/AudioRecorder.js +120 -0
- package/dist/client/audio/AudioRecorder.js.map +1 -0
- package/dist/client/audio/AudioVisualizer.d.ts +10 -0
- package/dist/client/audio/AudioVisualizer.d.ts.map +1 -0
- package/dist/client/audio/AudioVisualizer.js +2 -0
- package/dist/client/audio/AudioVisualizer.js.map +1 -0
- package/dist/client/audio/BlobAudioAnalyzer.d.ts +15 -0
- package/dist/client/audio/BlobAudioAnalyzer.d.ts.map +1 -0
- package/dist/client/audio/BlobAudioAnalyzer.js +110 -0
- package/dist/client/audio/BlobAudioAnalyzer.js.map +1 -0
- package/dist/client/audio/BlobTypes.d.ts +85 -0
- package/dist/client/audio/BlobTypes.d.ts.map +1 -0
- package/dist/client/audio/BlobTypes.js +109 -0
- package/dist/client/audio/BlobTypes.js.map +1 -0
- package/dist/client/audio/BlobVisualizer.d.ts +17 -0
- package/dist/client/audio/BlobVisualizer.d.ts.map +1 -0
- package/dist/client/audio/BlobVisualizer.js +152 -0
- package/dist/client/audio/BlobVisualizer.js.map +1 -0
- package/dist/client/audio/BlobVisualizerCore.d.ts +38 -0
- package/dist/client/audio/BlobVisualizerCore.d.ts.map +1 -0
- package/dist/client/audio/BlobVisualizerCore.js +239 -0
- package/dist/client/audio/BlobVisualizerCore.js.map +1 -0
- package/dist/client/audio/MicVisualizer.d.ts +7 -0
- package/dist/client/audio/MicVisualizer.d.ts.map +1 -0
- package/dist/client/audio/MicVisualizer.js +116 -0
- package/dist/client/audio/MicVisualizer.js.map +1 -0
- package/dist/client/audio/WaveVisualizer.d.ts +18 -0
- package/dist/client/audio/WaveVisualizer.d.ts.map +1 -0
- package/dist/client/audio/WaveVisualizer.js +54 -0
- package/dist/client/audio/WaveVisualizer.js.map +1 -0
- package/dist/client/audio/audioPlayer.worklet.d.ts +2 -0
- package/dist/client/audio/audioPlayer.worklet.d.ts.map +1 -0
- package/dist/client/audio/audioPlayer.worklet.js +46 -0
- package/dist/client/audio/audioPlayer.worklet.js.map +1 -0
- package/dist/client/audio/audioRecorder.worklet.d.ts +2 -0
- package/dist/client/audio/audioRecorder.worklet.d.ts.map +1 -0
- package/dist/client/audio/audioRecorder.worklet.js +28 -0
- package/dist/client/audio/audioRecorder.worklet.js.map +1 -0
- package/dist/client/audio/blob-styles/MetaballBlobStyle.d.ts +23 -0
- package/dist/client/audio/blob-styles/MetaballBlobStyle.d.ts.map +1 -0
- package/dist/client/audio/blob-styles/MetaballBlobStyle.js +238 -0
- package/dist/client/audio/blob-styles/MetaballBlobStyle.js.map +1 -0
- package/dist/client/audio/blob-styles/OrbsBlobStyle.d.ts +23 -0
- package/dist/client/audio/blob-styles/OrbsBlobStyle.d.ts.map +1 -0
- package/dist/client/audio/blob-styles/OrbsBlobStyle.js +244 -0
- package/dist/client/audio/blob-styles/OrbsBlobStyle.js.map +1 -0
- package/dist/client/audio/blob-styles/OrganicBlobStyle.d.ts +27 -0
- package/dist/client/audio/blob-styles/OrganicBlobStyle.d.ts.map +1 -0
- package/dist/client/audio/blob-styles/OrganicBlobStyle.js +290 -0
- package/dist/client/audio/blob-styles/OrganicBlobStyle.js.map +1 -0
- package/dist/client/audio/blob-styles/ParticleBlobStyle.d.ts +26 -0
- package/dist/client/audio/blob-styles/ParticleBlobStyle.d.ts.map +1 -0
- package/dist/client/audio/blob-styles/ParticleBlobStyle.js +297 -0
- package/dist/client/audio/blob-styles/ParticleBlobStyle.js.map +1 -0
- package/dist/client/audio/blob-styles/SiriBlobStyle.d.ts +23 -0
- package/dist/client/audio/blob-styles/SiriBlobStyle.d.ts.map +1 -0
- package/dist/client/audio/blob-styles/SiriBlobStyle.js +227 -0
- package/dist/client/audio/blob-styles/SiriBlobStyle.js.map +1 -0
- package/dist/client/audio/useSTT.d.ts +15 -0
- package/dist/client/audio/useSTT.d.ts.map +1 -0
- package/dist/client/audio/useSTT.js +124 -0
- package/dist/client/audio/useSTT.js.map +1 -0
- package/dist/client/audio/useTTS.d.ts +13 -0
- package/dist/client/audio/useTTS.d.ts.map +1 -0
- package/dist/client/audio/useTTS.js +78 -0
- package/dist/client/audio/useTTS.js.map +1 -0
- package/dist/client/bootstrapApp.d.ts +31 -0
- package/dist/client/bootstrapApp.d.ts.map +1 -0
- package/dist/client/bootstrapApp.js +55 -0
- package/dist/client/bootstrapApp.js.map +1 -0
- package/dist/client/callAI.d.ts +5 -0
- package/dist/client/callAI.d.ts.map +1 -0
- package/dist/client/callAI.js +52 -0
- package/dist/client/callAI.js.map +1 -0
- package/dist/client/components/Alert.d.ts +9 -0
- package/dist/client/components/Alert.d.ts.map +1 -0
- package/dist/client/components/Alert.js +60 -0
- package/dist/client/components/Alert.js.map +1 -0
- package/dist/client/components/AnimatedInput.d.ts +129 -0
- package/dist/client/components/AnimatedInput.d.ts.map +1 -0
- package/dist/client/components/AnimatedInput.js +264 -0
- package/dist/client/components/AnimatedInput.js.map +1 -0
- package/dist/client/components/AnimatedList.d.ts +32 -0
- package/dist/client/components/AnimatedList.d.ts.map +1 -0
- package/dist/client/components/AnimatedList.js +140 -0
- package/dist/client/components/AnimatedList.js.map +1 -0
- package/dist/client/components/AppScrollViewProvider.d.ts +41 -0
- package/dist/client/components/AppScrollViewProvider.d.ts.map +1 -0
- package/dist/client/components/AppScrollViewProvider.js +36 -0
- package/dist/client/components/AppScrollViewProvider.js.map +1 -0
- package/dist/client/components/Button.d.ts +25 -0
- package/dist/client/components/Button.d.ts.map +1 -0
- package/dist/client/components/Button.js +41 -0
- package/dist/client/components/Button.js.map +1 -0
- package/dist/client/components/Card.d.ts +8 -0
- package/dist/client/components/Card.d.ts.map +1 -0
- package/dist/client/components/Card.js +13 -0
- package/dist/client/components/Card.js.map +1 -0
- package/dist/client/components/CardStack.d.ts +48 -0
- package/dist/client/components/CardStack.d.ts.map +1 -0
- package/dist/client/components/CardStack.js +717 -0
- package/dist/client/components/CardStack.js.map +1 -0
- package/dist/client/components/CelebrationOverlay.d.ts +9 -0
- package/dist/client/components/CelebrationOverlay.d.ts.map +1 -0
- package/dist/client/components/CelebrationOverlay.js +91 -0
- package/dist/client/components/CelebrationOverlay.js.map +1 -0
- package/dist/client/components/Confetti.d.ts +11 -0
- package/dist/client/components/Confetti.d.ts.map +1 -0
- package/dist/client/components/Confetti.js +181 -0
- package/dist/client/components/Confetti.js.map +1 -0
- package/dist/client/components/DatePicker.d.ts +8 -0
- package/dist/client/components/DatePicker.d.ts.map +1 -0
- package/dist/client/components/DatePicker.js +27 -0
- package/dist/client/components/DatePicker.js.map +1 -0
- package/dist/client/components/DateRangePicker.d.ts +22 -0
- package/dist/client/components/DateRangePicker.d.ts.map +1 -0
- package/dist/client/components/DateRangePicker.js +215 -0
- package/dist/client/components/DateRangePicker.js.map +1 -0
- package/dist/client/components/DateTimePicker.d.ts +8 -0
- package/dist/client/components/DateTimePicker.d.ts.map +1 -0
- package/dist/client/components/DateTimePicker.js +38 -0
- package/dist/client/components/DateTimePicker.js.map +1 -0
- package/dist/client/components/DeviceSimulator.d.ts +5 -0
- package/dist/client/components/DeviceSimulator.d.ts.map +1 -0
- package/dist/client/components/DeviceSimulator.js +163 -0
- package/dist/client/components/DeviceSimulator.js.map +1 -0
- package/dist/client/components/DrawingCanvas.d.ts +16 -0
- package/dist/client/components/DrawingCanvas.d.ts.map +1 -0
- package/dist/client/components/DrawingCanvas.js +308 -0
- package/dist/client/components/DrawingCanvas.js.map +1 -0
- package/dist/client/components/EnumInput.d.ts +16 -0
- package/dist/client/components/EnumInput.d.ts.map +1 -0
- package/dist/client/components/EnumInput.js +26 -0
- package/dist/client/components/EnumInput.js.map +1 -0
- package/dist/client/components/FeedbackButton.d.ts +3 -0
- package/dist/client/components/FeedbackButton.d.ts.map +1 -0
- package/dist/client/components/FeedbackButton.js +120 -0
- package/dist/client/components/FeedbackButton.js.map +1 -0
- package/dist/client/components/FlatList.d.ts +47 -0
- package/dist/client/components/FlatList.d.ts.map +1 -0
- package/dist/client/components/FlatList.js +203 -0
- package/dist/client/components/FlatList.js.map +1 -0
- package/dist/client/components/Header.d.ts +10 -0
- package/dist/client/components/Header.d.ts.map +1 -0
- package/dist/client/components/Header.js +12 -0
- package/dist/client/components/Header.js.map +1 -0
- package/dist/client/components/Image.d.ts +20 -0
- package/dist/client/components/Image.d.ts.map +1 -0
- package/dist/client/components/Image.js +12 -0
- package/dist/client/components/Image.js.map +1 -0
- package/dist/client/components/Input.d.ts +15 -0
- package/dist/client/components/Input.d.ts.map +1 -0
- package/dist/client/components/Input.js +19 -0
- package/dist/client/components/Input.js.map +1 -0
- package/dist/client/components/KeyboardProvider.d.ts +17 -0
- package/dist/client/components/KeyboardProvider.d.ts.map +1 -0
- package/dist/client/components/KeyboardProvider.js +349 -0
- package/dist/client/components/KeyboardProvider.js.map +1 -0
- package/dist/client/components/LayoutSize.d.ts +25 -0
- package/dist/client/components/LayoutSize.d.ts.map +1 -0
- package/dist/client/components/LayoutSize.js +107 -0
- package/dist/client/components/LayoutSize.js.map +1 -0
- package/dist/client/components/Loading.d.ts +10 -0
- package/dist/client/components/Loading.d.ts.map +1 -0
- package/dist/client/components/Loading.js +59 -0
- package/dist/client/components/Loading.js.map +1 -0
- package/dist/client/components/Modal.d.ts +10 -0
- package/dist/client/components/Modal.d.ts.map +1 -0
- package/dist/client/components/Modal.js +19 -0
- package/dist/client/components/Modal.js.map +1 -0
- package/dist/client/components/PageLayout.d.ts +17 -0
- package/dist/client/components/PageLayout.d.ts.map +1 -0
- package/dist/client/components/PageLayout.js +30 -0
- package/dist/client/components/PageLayout.js.map +1 -0
- package/dist/client/components/Pager.d.ts +17 -0
- package/dist/client/components/Pager.d.ts.map +1 -0
- package/dist/client/components/Pager.js +250 -0
- package/dist/client/components/Pager.js.map +1 -0
- package/dist/client/components/Panel.d.ts +7 -0
- package/dist/client/components/Panel.d.ts.map +1 -0
- package/dist/client/components/Panel.js +10 -0
- package/dist/client/components/Panel.js.map +1 -0
- package/dist/client/components/PopupPanel.d.ts +9 -0
- package/dist/client/components/PopupPanel.d.ts.map +1 -0
- package/dist/client/components/PopupPanel.js +14 -0
- package/dist/client/components/PopupPanel.js.map +1 -0
- package/dist/client/components/Pressable.d.ts +15 -0
- package/dist/client/components/Pressable.d.ts.map +1 -0
- package/dist/client/components/Pressable.js +14 -0
- package/dist/client/components/Pressable.js.map +1 -0
- package/dist/client/components/ResponsiveGrid.d.ts +15 -0
- package/dist/client/components/ResponsiveGrid.d.ts.map +1 -0
- package/dist/client/components/ResponsiveGrid.js +38 -0
- package/dist/client/components/ResponsiveGrid.js.map +1 -0
- package/dist/client/components/ScrollAnimatedView.d.ts +17 -0
- package/dist/client/components/ScrollAnimatedView.d.ts.map +1 -0
- package/dist/client/components/ScrollAnimatedView.js +26 -0
- package/dist/client/components/ScrollAnimatedView.js.map +1 -0
- package/dist/client/components/ScrollDownArrow.d.ts +4 -0
- package/dist/client/components/ScrollDownArrow.d.ts.map +1 -0
- package/dist/client/components/ScrollDownArrow.js +43 -0
- package/dist/client/components/ScrollDownArrow.js.map +1 -0
- package/dist/client/components/ScrollIndicator.d.ts +2 -0
- package/dist/client/components/ScrollIndicator.d.ts.map +1 -0
- package/dist/client/components/ScrollIndicator.js +69 -0
- package/dist/client/components/ScrollIndicator.js.map +1 -0
- package/dist/client/components/ScrollView.d.ts +23 -0
- package/dist/client/components/ScrollView.d.ts.map +1 -0
- package/dist/client/components/ScrollView.js +169 -0
- package/dist/client/components/ScrollView.js.map +1 -0
- package/dist/client/components/SelectView.d.ts +37 -0
- package/dist/client/components/SelectView.d.ts.map +1 -0
- package/dist/client/components/SelectView.js +170 -0
- package/dist/client/components/SelectView.js.map +1 -0
- package/dist/client/components/SettingGroup.d.ts +10 -0
- package/dist/client/components/SettingGroup.d.ts.map +1 -0
- package/dist/client/components/SettingGroup.js +21 -0
- package/dist/client/components/SettingGroup.js.map +1 -0
- package/dist/client/components/SimpleScrollView.d.ts +15 -0
- package/dist/client/components/SimpleScrollView.d.ts.map +1 -0
- package/dist/client/components/SimpleScrollView.js +66 -0
- package/dist/client/components/SimpleScrollView.js.map +1 -0
- package/dist/client/components/TabPicker.d.ts +41 -0
- package/dist/client/components/TabPicker.d.ts.map +1 -0
- package/dist/client/components/TabPicker.js +189 -0
- package/dist/client/components/TabPicker.js.map +1 -0
- package/dist/client/components/Text.d.ts +23 -0
- package/dist/client/components/Text.d.ts.map +1 -0
- package/dist/client/components/Text.js +43 -0
- package/dist/client/components/Text.js.map +1 -0
- package/dist/client/components/Toast.d.ts +10 -0
- package/dist/client/components/Toast.d.ts.map +1 -0
- package/dist/client/components/Toast.js +21 -0
- package/dist/client/components/Toast.js.map +1 -0
- package/dist/client/components/ValidatedTextInput.d.ts +40 -0
- package/dist/client/components/ValidatedTextInput.d.ts.map +1 -0
- package/dist/client/components/ValidatedTextInput.js +336 -0
- package/dist/client/components/ValidatedTextInput.js.map +1 -0
- package/dist/client/components/View.d.ts +11 -0
- package/dist/client/components/View.d.ts.map +1 -0
- package/dist/client/components/View.js +16 -0
- package/dist/client/components/View.js.map +1 -0
- package/dist/client/components/WheelPicker.d.ts +10 -0
- package/dist/client/components/WheelPicker.d.ts.map +1 -0
- package/dist/client/components/WheelPicker.js +124 -0
- package/dist/client/components/WheelPicker.js.map +1 -0
- package/dist/client/components/WizardView.d.ts +51 -0
- package/dist/client/components/WizardView.d.ts.map +1 -0
- package/dist/client/components/WizardView.js +171 -0
- package/dist/client/components/WizardView.js.map +1 -0
- package/dist/client/components/ZoomPanPinch.d.ts +26 -0
- package/dist/client/components/ZoomPanPinch.d.ts.map +1 -0
- package/dist/client/components/ZoomPanPinch.js +290 -0
- package/dist/client/components/ZoomPanPinch.js.map +1 -0
- package/dist/client/components/index.d.ts +79 -0
- package/dist/client/components/index.d.ts.map +1 -0
- package/dist/client/components/index.js +45 -0
- package/dist/client/components/index.js.map +1 -0
- package/dist/client/components/zIndex.d.ts +10 -0
- package/dist/client/components/zIndex.d.ts.map +1 -0
- package/dist/client/components/zIndex.js +12 -0
- package/dist/client/components/zIndex.js.map +1 -0
- package/dist/client/createHttpClient.d.ts +13 -0
- package/dist/client/createHttpClient.d.ts.map +1 -0
- package/dist/client/createHttpClient.js +24 -0
- package/dist/client/createHttpClient.js.map +1 -0
- package/dist/client/createSocket.d.ts +83 -0
- package/dist/client/createSocket.d.ts.map +1 -0
- package/dist/client/createSocket.js +497 -0
- package/dist/client/createSocket.js.map +1 -0
- package/dist/client/index.d.ts +51 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +34 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/uglyBotSocket.d.ts +13 -0
- package/dist/client/uglyBotSocket.d.ts.map +1 -0
- package/dist/client/uglyBotSocket.js +111 -0
- package/dist/client/uglyBotSocket.js.map +1 -0
- package/dist/collab/client/CollabProvider.d.ts +36 -0
- package/dist/collab/client/CollabProvider.d.ts.map +1 -0
- package/dist/collab/client/CollabProvider.js +152 -0
- package/dist/collab/client/CollabProvider.js.map +1 -0
- package/dist/collab/client/collabUtils.d.ts +3 -0
- package/dist/collab/client/collabUtils.d.ts.map +1 -0
- package/dist/collab/client/collabUtils.js +17 -0
- package/dist/collab/client/collabUtils.js.map +1 -0
- package/dist/collab/client/index.d.ts +5 -0
- package/dist/collab/client/index.d.ts.map +1 -0
- package/dist/collab/client/index.js +4 -0
- package/dist/collab/client/index.js.map +1 -0
- package/dist/collab/client/useCollab.d.ts +14 -0
- package/dist/collab/client/useCollab.d.ts.map +1 -0
- package/dist/collab/client/useCollab.js +38 -0
- package/dist/collab/client/useCollab.js.map +1 -0
- package/dist/collab/server/CollabServer.d.ts +64 -0
- package/dist/collab/server/CollabServer.d.ts.map +1 -0
- package/dist/collab/server/CollabServer.js +383 -0
- package/dist/collab/server/CollabServer.js.map +1 -0
- package/dist/collab/server/index.d.ts +20 -0
- package/dist/collab/server/index.d.ts.map +1 -0
- package/dist/collab/server/index.js +21 -0
- package/dist/collab/server/index.js.map +1 -0
- package/dist/collab/shared/CollabTypes.d.ts +31 -0
- package/dist/collab/shared/CollabTypes.d.ts.map +1 -0
- package/dist/collab/shared/CollabTypes.js +3 -0
- package/dist/collab/shared/CollabTypes.js.map +1 -0
- package/dist/conversation/client/ChatContext.d.ts +23 -0
- package/dist/conversation/client/ChatContext.d.ts.map +1 -0
- package/dist/conversation/client/ChatContext.js +9 -0
- package/dist/conversation/client/ChatContext.js.map +1 -0
- package/dist/conversation/client/ChatMarkdownContent.d.ts +7 -0
- package/dist/conversation/client/ChatMarkdownContent.d.ts.map +1 -0
- package/dist/conversation/client/ChatMarkdownContent.js +6 -0
- package/dist/conversation/client/ChatMarkdownContent.js.map +1 -0
- package/dist/conversation/client/ChatMarkdownInput.d.ts +8 -0
- package/dist/conversation/client/ChatMarkdownInput.d.ts.map +1 -0
- package/dist/conversation/client/ChatMarkdownInput.js +23 -0
- package/dist/conversation/client/ChatMarkdownInput.js.map +1 -0
- package/dist/conversation/client/ChatMessageBubble.d.ts +7 -0
- package/dist/conversation/client/ChatMessageBubble.d.ts.map +1 -0
- package/dist/conversation/client/ChatMessageBubble.js +93 -0
- package/dist/conversation/client/ChatMessageBubble.js.map +1 -0
- package/dist/conversation/client/ChatScrollButton.d.ts +6 -0
- package/dist/conversation/client/ChatScrollButton.d.ts.map +1 -0
- package/dist/conversation/client/ChatScrollButton.js +35 -0
- package/dist/conversation/client/ChatScrollButton.js.map +1 -0
- package/dist/conversation/client/ChatTextContent.d.ts +5 -0
- package/dist/conversation/client/ChatTextContent.d.ts.map +1 -0
- package/dist/conversation/client/ChatTextContent.js +9 -0
- package/dist/conversation/client/ChatTextContent.js.map +1 -0
- package/dist/conversation/client/ChatTextInput.d.ts +7 -0
- package/dist/conversation/client/ChatTextInput.d.ts.map +1 -0
- package/dist/conversation/client/ChatTextInput.js +39 -0
- package/dist/conversation/client/ChatTextInput.js.map +1 -0
- package/dist/conversation/client/ChatTypingIndicator.d.ts +2 -0
- package/dist/conversation/client/ChatTypingIndicator.d.ts.map +1 -0
- package/dist/conversation/client/ChatTypingIndicator.js +45 -0
- package/dist/conversation/client/ChatTypingIndicator.js.map +1 -0
- package/dist/conversation/client/ChatView.d.ts +21 -0
- package/dist/conversation/client/ChatView.d.ts.map +1 -0
- package/dist/conversation/client/ChatView.js +154 -0
- package/dist/conversation/client/ChatView.js.map +1 -0
- package/dist/conversation/client/index.d.ts +18 -0
- package/dist/conversation/client/index.d.ts.map +1 -0
- package/dist/conversation/client/index.js +10 -0
- package/dist/conversation/client/index.js.map +1 -0
- package/dist/conversation/server/Conversation.d.ts +108 -0
- package/dist/conversation/server/Conversation.d.ts.map +1 -0
- package/dist/conversation/server/Conversation.js +1611 -0
- package/dist/conversation/server/Conversation.js.map +1 -0
- package/dist/conversation/server/ConversationDeps.d.ts +65 -0
- package/dist/conversation/server/ConversationDeps.d.ts.map +1 -0
- package/dist/conversation/server/ConversationDeps.js +3 -0
- package/dist/conversation/server/ConversationDeps.js.map +1 -0
- package/dist/conversation/server/ConversationServer.d.ts +46 -0
- package/dist/conversation/server/ConversationServer.d.ts.map +1 -0
- package/dist/conversation/server/ConversationServer.js +250 -0
- package/dist/conversation/server/ConversationServer.js.map +1 -0
- package/dist/conversation/server/ConversationUser.d.ts +23 -0
- package/dist/conversation/server/ConversationUser.d.ts.map +1 -0
- package/dist/conversation/server/ConversationUser.js +453 -0
- package/dist/conversation/server/ConversationUser.js.map +1 -0
- package/dist/conversation/server/index.d.ts +21 -0
- package/dist/conversation/server/index.d.ts.map +1 -0
- package/dist/conversation/server/index.js +28 -0
- package/dist/conversation/server/index.js.map +1 -0
- package/dist/conversation/server/types.d.ts +96 -0
- package/dist/conversation/server/types.d.ts.map +1 -0
- package/dist/conversation/server/types.js +9 -0
- package/dist/conversation/server/types.js.map +1 -0
- package/dist/conversation/shared/index.d.ts +3 -0
- package/dist/conversation/shared/index.d.ts.map +1 -0
- package/dist/conversation/shared/index.js +2 -0
- package/dist/conversation/shared/index.js.map +1 -0
- package/dist/conversation/shared/types.d.ts +91 -0
- package/dist/conversation/shared/types.d.ts.map +1 -0
- package/dist/conversation/shared/types.js +30 -0
- package/dist/conversation/shared/types.js.map +1 -0
- package/dist/eslint/index.d.ts +8 -0
- package/dist/eslint/index.d.ts.map +1 -0
- package/dist/eslint/index.js +68 -0
- package/dist/eslint/index.js.map +1 -0
- package/dist/eslint/requireDataId.d.ts +8 -0
- package/dist/eslint/requireDataId.d.ts.map +1 -0
- package/dist/eslint/requireDataId.js +77 -0
- package/dist/eslint/requireDataId.js.map +1 -0
- package/dist/markdown/client/CodeMirrorEditor.d.ts +8 -0
- package/dist/markdown/client/CodeMirrorEditor.d.ts.map +1 -0
- package/dist/markdown/client/CodeMirrorEditor.js +88 -0
- package/dist/markdown/client/CodeMirrorEditor.js.map +1 -0
- package/dist/markdown/client/EditorModeToggle.d.ts +8 -0
- package/dist/markdown/client/EditorModeToggle.d.ts.map +1 -0
- package/dist/markdown/client/EditorModeToggle.js +9 -0
- package/dist/markdown/client/EditorModeToggle.js.map +1 -0
- package/dist/markdown/client/MarkdownContext.d.ts +10 -0
- package/dist/markdown/client/MarkdownContext.d.ts.map +1 -0
- package/dist/markdown/client/MarkdownContext.js +18 -0
- package/dist/markdown/client/MarkdownContext.js.map +1 -0
- package/dist/markdown/client/MarkdownEditor.d.ts +82 -0
- package/dist/markdown/client/MarkdownEditor.d.ts.map +1 -0
- package/dist/markdown/client/MarkdownEditor.js +7 -0
- package/dist/markdown/client/MarkdownEditor.js.map +1 -0
- package/dist/markdown/client/MarkdownEditorInternal.d.ts +19 -0
- package/dist/markdown/client/MarkdownEditorInternal.d.ts.map +1 -0
- package/dist/markdown/client/MarkdownEditorInternal.js +905 -0
- package/dist/markdown/client/MarkdownEditorInternal.js.map +1 -0
- package/dist/markdown/client/MarkdownTheme.css +907 -0
- package/dist/markdown/client/MarkdownViewer.d.ts +41 -0
- package/dist/markdown/client/MarkdownViewer.d.ts.map +1 -0
- package/dist/markdown/client/MarkdownViewer.js +29 -0
- package/dist/markdown/client/MarkdownViewer.js.map +1 -0
- package/dist/markdown/client/MdastViewer.d.ts +39 -0
- package/dist/markdown/client/MdastViewer.d.ts.map +1 -0
- package/dist/markdown/client/MdastViewer.js +472 -0
- package/dist/markdown/client/MdastViewer.js.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/CommentGutter.d.ts +24 -0
- package/dist/markdown/client/ProseMirrorEditor/CommentGutter.d.ts.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/CommentGutter.js +109 -0
- package/dist/markdown/client/ProseMirrorEditor/CommentGutter.js.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/EditorContextMenu.d.ts +24 -0
- package/dist/markdown/client/ProseMirrorEditor/EditorContextMenu.d.ts.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/EditorContextMenu.js +463 -0
- package/dist/markdown/client/ProseMirrorEditor/EditorContextMenu.js.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/FloatingToolbar.d.ts +29 -0
- package/dist/markdown/client/ProseMirrorEditor/FloatingToolbar.d.ts.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/FloatingToolbar.js +314 -0
- package/dist/markdown/client/ProseMirrorEditor/FloatingToolbar.js.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/SlashCommandMenu.d.ts +23 -0
- package/dist/markdown/client/ProseMirrorEditor/SlashCommandMenu.d.ts.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/SlashCommandMenu.js +395 -0
- package/dist/markdown/client/ProseMirrorEditor/SlashCommandMenu.js.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/TableOfContents.d.ts +13 -0
- package/dist/markdown/client/ProseMirrorEditor/TableOfContents.d.ts.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/TableOfContents.js +83 -0
- package/dist/markdown/client/ProseMirrorEditor/TableOfContents.js.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/TableToolbar.d.ts +17 -0
- package/dist/markdown/client/ProseMirrorEditor/TableToolbar.d.ts.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/TableToolbar.js +156 -0
- package/dist/markdown/client/ProseMirrorEditor/TableToolbar.js.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/commands.d.ts +158 -0
- package/dist/markdown/client/ProseMirrorEditor/commands.d.ts.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/commands.js +541 -0
- package/dist/markdown/client/ProseMirrorEditor/commands.js.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/index.d.ts +37 -0
- package/dist/markdown/client/ProseMirrorEditor/index.d.ts.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/index.js +227 -0
- package/dist/markdown/client/ProseMirrorEditor/index.js.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/mdastExport.d.ts +17 -0
- package/dist/markdown/client/ProseMirrorEditor/mdastExport.d.ts.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/mdastExport.js +430 -0
- package/dist/markdown/client/ProseMirrorEditor/mdastExport.js.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/mdastImport.d.ts +17 -0
- package/dist/markdown/client/ProseMirrorEditor/mdastImport.d.ts.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/mdastImport.js +352 -0
- package/dist/markdown/client/ProseMirrorEditor/mdastImport.js.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/nodeViews/DiagramFullscreen.d.ts +2 -0
- package/dist/markdown/client/ProseMirrorEditor/nodeViews/DiagramFullscreen.d.ts.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/nodeViews/DiagramFullscreen.js +257 -0
- package/dist/markdown/client/ProseMirrorEditor/nodeViews/DiagramFullscreen.js.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/nodeViews/LatexNodeView.d.ts +39 -0
- package/dist/markdown/client/ProseMirrorEditor/nodeViews/LatexNodeView.d.ts.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/nodeViews/LatexNodeView.js +234 -0
- package/dist/markdown/client/ProseMirrorEditor/nodeViews/LatexNodeView.js.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/nodeViews/MarkmapNodeView.d.ts +38 -0
- package/dist/markdown/client/ProseMirrorEditor/nodeViews/MarkmapNodeView.d.ts.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/nodeViews/MarkmapNodeView.js +250 -0
- package/dist/markdown/client/ProseMirrorEditor/nodeViews/MarkmapNodeView.js.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/nodeViews/MermaidNodeView.d.ts +38 -0
- package/dist/markdown/client/ProseMirrorEditor/nodeViews/MermaidNodeView.d.ts.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/nodeViews/MermaidNodeView.js +194 -0
- package/dist/markdown/client/ProseMirrorEditor/nodeViews/MermaidNodeView.js.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/nodeViews/SvgNodeView.d.ts +36 -0
- package/dist/markdown/client/ProseMirrorEditor/nodeViews/SvgNodeView.d.ts.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/nodeViews/SvgNodeView.js +157 -0
- package/dist/markdown/client/ProseMirrorEditor/nodeViews/SvgNodeView.js.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/nodeViews/VegaLiteNodeView.d.ts +37 -0
- package/dist/markdown/client/ProseMirrorEditor/nodeViews/VegaLiteNodeView.d.ts.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/nodeViews/VegaLiteNodeView.js +184 -0
- package/dist/markdown/client/ProseMirrorEditor/nodeViews/VegaLiteNodeView.js.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/pastePlugin.d.ts +17 -0
- package/dist/markdown/client/ProseMirrorEditor/pastePlugin.d.ts.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/pastePlugin.js +248 -0
- package/dist/markdown/client/ProseMirrorEditor/pastePlugin.js.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/plugins/followPlugin.d.ts +29 -0
- package/dist/markdown/client/ProseMirrorEditor/plugins/followPlugin.d.ts.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/plugins/followPlugin.js +72 -0
- package/dist/markdown/client/ProseMirrorEditor/plugins/followPlugin.js.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/plugins/imagePlugin.d.ts +42 -0
- package/dist/markdown/client/ProseMirrorEditor/plugins/imagePlugin.d.ts.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/plugins/imagePlugin.js +355 -0
- package/dist/markdown/client/ProseMirrorEditor/plugins/imagePlugin.js.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/plugins/mentionPlugin.d.ts +47 -0
- package/dist/markdown/client/ProseMirrorEditor/plugins/mentionPlugin.d.ts.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/plugins/mentionPlugin.js +433 -0
- package/dist/markdown/client/ProseMirrorEditor/plugins/mentionPlugin.js.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/plugins/slashCommandPlugin.d.ts +35 -0
- package/dist/markdown/client/ProseMirrorEditor/plugins/slashCommandPlugin.d.ts.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/plugins/slashCommandPlugin.js +159 -0
- package/dist/markdown/client/ProseMirrorEditor/plugins/slashCommandPlugin.js.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/plugins/syntaxHighlightPlugin.d.ts +12 -0
- package/dist/markdown/client/ProseMirrorEditor/plugins/syntaxHighlightPlugin.d.ts.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/plugins/syntaxHighlightPlugin.js +138 -0
- package/dist/markdown/client/ProseMirrorEditor/plugins/syntaxHighlightPlugin.js.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/plugins/tablePlugin.d.ts +29 -0
- package/dist/markdown/client/ProseMirrorEditor/plugins/tablePlugin.d.ts.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/plugins/tablePlugin.js +127 -0
- package/dist/markdown/client/ProseMirrorEditor/plugins/tablePlugin.js.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/schema.d.ts +47 -0
- package/dist/markdown/client/ProseMirrorEditor/schema.d.ts.map +1 -0
- package/dist/markdown/client/ProseMirrorEditor/schema.js +524 -0
- package/dist/markdown/client/ProseMirrorEditor/schema.js.map +1 -0
- package/dist/markdown/client/frameworkImports.d.ts +9 -0
- package/dist/markdown/client/frameworkImports.d.ts.map +1 -0
- package/dist/markdown/client/frameworkImports.js +8 -0
- package/dist/markdown/client/frameworkImports.js.map +1 -0
- package/dist/markdown/client/index.d.ts +12 -0
- package/dist/markdown/client/index.d.ts.map +1 -0
- package/dist/markdown/client/index.js +15 -0
- package/dist/markdown/client/index.js.map +1 -0
- package/dist/markdown/client/markdownComponents.d.ts +32 -0
- package/dist/markdown/client/markdownComponents.d.ts.map +1 -0
- package/dist/markdown/client/markdownComponents.js +51 -0
- package/dist/markdown/client/markdownComponents.js.map +1 -0
- package/dist/markdown/client/markdownIcons.d.ts +38 -0
- package/dist/markdown/client/markdownIcons.d.ts.map +1 -0
- package/dist/markdown/client/markdownIcons.js +32 -0
- package/dist/markdown/client/markdownIcons.js.map +1 -0
- package/dist/markdown/client/markdownUtils.d.ts +18 -0
- package/dist/markdown/client/markdownUtils.d.ts.map +1 -0
- package/dist/markdown/client/markdownUtils.js +62 -0
- package/dist/markdown/client/markdownUtils.js.map +1 -0
- package/dist/markdown/client/ui.module.css +1475 -0
- package/dist/markdown/shared/Comments.d.ts +16 -0
- package/dist/markdown/shared/Comments.d.ts.map +1 -0
- package/dist/markdown/shared/Comments.js +122 -0
- package/dist/markdown/shared/Comments.js.map +1 -0
- package/dist/markdown/shared/KatexLazy.d.ts +41 -0
- package/dist/markdown/shared/KatexLazy.d.ts.map +1 -0
- package/dist/markdown/shared/KatexLazy.js +104 -0
- package/dist/markdown/shared/KatexLazy.js.map +1 -0
- package/dist/markdown/shared/MdastParser.d.ts +59 -0
- package/dist/markdown/shared/MdastParser.d.ts.map +1 -0
- package/dist/markdown/shared/MdastParser.js +695 -0
- package/dist/markdown/shared/MdastParser.js.map +1 -0
- package/dist/markdown/shared/MdastTypes.d.ts +202 -0
- package/dist/markdown/shared/MdastTypes.d.ts.map +1 -0
- package/dist/markdown/shared/MdastTypes.js +9 -0
- package/dist/markdown/shared/MdastTypes.js.map +1 -0
- package/dist/markdown/shared/index.d.ts +6 -0
- package/dist/markdown/shared/index.d.ts.map +1 -0
- package/dist/markdown/shared/index.js +4 -0
- package/dist/markdown/shared/index.js.map +1 -0
- package/dist/playwright/index.d.ts +16 -0
- package/dist/playwright/index.d.ts.map +1 -0
- package/dist/playwright/index.js +32 -0
- package/dist/playwright/index.js.map +1 -0
- package/dist/server/App.d.ts +104 -0
- package/dist/server/App.d.ts.map +1 -0
- package/dist/server/App.js +1128 -0
- package/dist/server/App.js.map +1 -0
- package/dist/server/Auth.d.ts +38 -0
- package/dist/server/Auth.d.ts.map +1 -0
- package/dist/server/Auth.js +190 -0
- package/dist/server/Auth.js.map +1 -0
- package/dist/server/Cache.d.ts +47 -0
- package/dist/server/Cache.d.ts.map +1 -0
- package/dist/server/Cache.js +130 -0
- package/dist/server/Cache.js.map +1 -0
- package/dist/server/DB.d.ts +35 -0
- package/dist/server/DB.d.ts.map +1 -0
- package/dist/server/DB.js +283 -0
- package/dist/server/DB.js.map +1 -0
- package/dist/server/DataProxyClient.d.ts +81 -0
- package/dist/server/DataProxyClient.d.ts.map +1 -0
- package/dist/server/DataProxyClient.js +628 -0
- package/dist/server/DataProxyClient.js.map +1 -0
- package/dist/server/Email.d.ts +44 -0
- package/dist/server/Email.d.ts.map +1 -0
- package/dist/server/Email.js +59 -0
- package/dist/server/Email.js.map +1 -0
- package/dist/server/EmailTemplate.d.ts +17 -0
- package/dist/server/EmailTemplate.d.ts.map +1 -0
- package/dist/server/EmailTemplate.js +29 -0
- package/dist/server/EmailTemplate.js.map +1 -0
- package/dist/server/EventCounter.d.ts +23 -0
- package/dist/server/EventCounter.d.ts.map +1 -0
- package/dist/server/EventCounter.js +172 -0
- package/dist/server/EventCounter.js.map +1 -0
- package/dist/server/EventLogAdmin.d.ts +110 -0
- package/dist/server/EventLogAdmin.d.ts.map +1 -0
- package/dist/server/EventLogAdmin.js +281 -0
- package/dist/server/EventLogAdmin.js.map +1 -0
- package/dist/server/ExperimentAdmin.d.ts +24 -0
- package/dist/server/ExperimentAdmin.d.ts.map +1 -0
- package/dist/server/ExperimentAdmin.js +84 -0
- package/dist/server/ExperimentAdmin.js.map +1 -0
- package/dist/server/ImageGen.d.ts +5 -0
- package/dist/server/ImageGen.d.ts.map +1 -0
- package/dist/server/ImageGen.js +5 -0
- package/dist/server/ImageGen.js.map +1 -0
- package/dist/server/Logging.d.ts +102 -0
- package/dist/server/Logging.d.ts.map +1 -0
- package/dist/server/Logging.js +490 -0
- package/dist/server/Logging.js.map +1 -0
- package/dist/server/Nats.d.ts +71 -0
- package/dist/server/Nats.d.ts.map +1 -0
- package/dist/server/Nats.js +119 -0
- package/dist/server/Nats.js.map +1 -0
- package/dist/server/NatsProxyClient.d.ts +62 -0
- package/dist/server/NatsProxyClient.d.ts.map +1 -0
- package/dist/server/NatsProxyClient.js +353 -0
- package/dist/server/NatsProxyClient.js.map +1 -0
- package/dist/server/NatsStore.d.ts +35 -0
- package/dist/server/NatsStore.d.ts.map +1 -0
- package/dist/server/NatsStore.js +104 -0
- package/dist/server/NatsStore.js.map +1 -0
- package/dist/server/PushNotification.d.ts +27 -0
- package/dist/server/PushNotification.d.ts.map +1 -0
- package/dist/server/PushNotification.js +73 -0
- package/dist/server/PushNotification.js.map +1 -0
- package/dist/server/PushSend.d.ts +20 -0
- package/dist/server/PushSend.d.ts.map +1 -0
- package/dist/server/PushSend.js +17 -0
- package/dist/server/PushSend.js.map +1 -0
- package/dist/server/RateLimit.d.ts +30 -0
- package/dist/server/RateLimit.d.ts.map +1 -0
- package/dist/server/RateLimit.js +231 -0
- package/dist/server/RateLimit.js.map +1 -0
- package/dist/server/Router.d.ts +20 -0
- package/dist/server/Router.d.ts.map +1 -0
- package/dist/server/Router.js +85 -0
- package/dist/server/Router.js.map +1 -0
- package/dist/server/SchemaCheck.d.ts +23 -0
- package/dist/server/SchemaCheck.d.ts.map +1 -0
- package/dist/server/SchemaCheck.js +151 -0
- package/dist/server/SchemaCheck.js.map +1 -0
- package/dist/server/Socket.d.ts +13 -0
- package/dist/server/Socket.d.ts.map +1 -0
- package/dist/server/Socket.js +376 -0
- package/dist/server/Socket.js.map +1 -0
- package/dist/server/StoreHandlers.d.ts +4 -0
- package/dist/server/StoreHandlers.d.ts.map +1 -0
- package/dist/server/StoreHandlers.js +169 -0
- package/dist/server/StoreHandlers.js.map +1 -0
- package/dist/server/Strings.d.ts +33 -0
- package/dist/server/Strings.d.ts.map +1 -0
- package/dist/server/Strings.js +31 -0
- package/dist/server/Strings.js.map +1 -0
- package/dist/server/TextGen.d.ts +5 -0
- package/dist/server/TextGen.d.ts.map +1 -0
- package/dist/server/TextGen.js +6 -0
- package/dist/server/TextGen.js.map +1 -0
- package/dist/server/User.d.ts +10 -0
- package/dist/server/User.d.ts.map +1 -0
- package/dist/server/User.js +8 -0
- package/dist/server/User.js.map +1 -0
- package/dist/server/ai/ImageGenBase.d.ts +35 -0
- package/dist/server/ai/ImageGenBase.d.ts.map +1 -0
- package/dist/server/ai/ImageGenBase.js +2 -0
- package/dist/server/ai/ImageGenBase.js.map +1 -0
- package/dist/server/ai/ImageGenClient.d.ts +6 -0
- package/dist/server/ai/ImageGenClient.d.ts.map +1 -0
- package/dist/server/ai/ImageGenClient.js +11 -0
- package/dist/server/ai/ImageGenClient.js.map +1 -0
- package/dist/server/ai/ProviderBalance.d.ts +18 -0
- package/dist/server/ai/ProviderBalance.d.ts.map +1 -0
- package/dist/server/ai/ProviderBalance.js +15 -0
- package/dist/server/ai/ProviderBalance.js.map +1 -0
- package/dist/server/ai/TextGenBase.d.ts +212 -0
- package/dist/server/ai/TextGenBase.d.ts.map +1 -0
- package/dist/server/ai/TextGenBase.js +30 -0
- package/dist/server/ai/TextGenBase.js.map +1 -0
- package/dist/server/ai/TextGenClient.d.ts +9 -0
- package/dist/server/ai/TextGenClient.d.ts.map +1 -0
- package/dist/server/ai/TextGenClient.js +25 -0
- package/dist/server/ai/TextGenClient.js.map +1 -0
- package/dist/server/ai/WebSearchClient.d.ts +9 -0
- package/dist/server/ai/WebSearchClient.d.ts.map +1 -0
- package/dist/server/ai/WebSearchClient.js +20 -0
- package/dist/server/ai/WebSearchClient.js.map +1 -0
- package/dist/server/ai/index.d.ts +17 -0
- package/dist/server/ai/index.d.ts.map +1 -0
- package/dist/server/ai/index.js +20 -0
- package/dist/server/ai/index.js.map +1 -0
- package/dist/server/ai/providers/UglyBotImageGenProvider.d.ts +3 -0
- package/dist/server/ai/providers/UglyBotImageGenProvider.d.ts.map +1 -0
- package/dist/server/ai/providers/UglyBotImageGenProvider.js +23 -0
- package/dist/server/ai/providers/UglyBotImageGenProvider.js.map +1 -0
- package/dist/server/ai/providers/UglyBotTextGenProvider.d.ts +3 -0
- package/dist/server/ai/providers/UglyBotTextGenProvider.d.ts.map +1 -0
- package/dist/server/ai/providers/UglyBotTextGenProvider.js +54 -0
- package/dist/server/ai/providers/UglyBotTextGenProvider.js.map +1 -0
- package/dist/server/ai/providers/UglyBotWebSearchProvider.d.ts +3 -0
- package/dist/server/ai/providers/UglyBotWebSearchProvider.d.ts.map +1 -0
- package/dist/server/ai/providers/UglyBotWebSearchProvider.js +26 -0
- package/dist/server/ai/providers/UglyBotWebSearchProvider.js.map +1 -0
- package/dist/server/ai/types.d.ts +185 -0
- package/dist/server/ai/types.d.ts.map +1 -0
- package/dist/server/ai/types.js +17 -0
- package/dist/server/ai/types.js.map +1 -0
- package/dist/server/billing/BillingAlert.d.ts +31 -0
- package/dist/server/billing/BillingAlert.d.ts.map +1 -0
- package/dist/server/billing/BillingAlert.js +107 -0
- package/dist/server/billing/BillingAlert.js.map +1 -0
- package/dist/server/billing/BillingGateway.d.ts +51 -0
- package/dist/server/billing/BillingGateway.d.ts.map +1 -0
- package/dist/server/billing/BillingGateway.js +179 -0
- package/dist/server/billing/BillingGateway.js.map +1 -0
- package/dist/server/billing/BillingLedger.d.ts +67 -0
- package/dist/server/billing/BillingLedger.d.ts.map +1 -0
- package/dist/server/billing/BillingLedger.js +214 -0
- package/dist/server/billing/BillingLedger.js.map +1 -0
- package/dist/server/billing/CreditStore.d.ts +60 -0
- package/dist/server/billing/CreditStore.d.ts.map +1 -0
- package/dist/server/billing/CreditStore.js +114 -0
- package/dist/server/billing/CreditStore.js.map +1 -0
- package/dist/server/billing/LimitEnforcer.d.ts +73 -0
- package/dist/server/billing/LimitEnforcer.d.ts.map +1 -0
- package/dist/server/billing/LimitEnforcer.js +276 -0
- package/dist/server/billing/LimitEnforcer.js.map +1 -0
- package/dist/server/billing/UserLimitCache.d.ts +35 -0
- package/dist/server/billing/UserLimitCache.d.ts.map +1 -0
- package/dist/server/billing/UserLimitCache.js +91 -0
- package/dist/server/billing/UserLimitCache.js.map +1 -0
- package/dist/server/billing/index.d.ts +7 -0
- package/dist/server/billing/index.d.ts.map +1 -0
- package/dist/server/billing/index.js +5 -0
- package/dist/server/billing/index.js.map +1 -0
- package/dist/server/billing/types.d.ts +126 -0
- package/dist/server/billing/types.d.ts.map +1 -0
- package/dist/server/billing/types.js +97 -0
- package/dist/server/billing/types.js.map +1 -0
- package/dist/server/bootstrap.d.ts +34 -0
- package/dist/server/bootstrap.d.ts.map +1 -0
- package/dist/server/bootstrap.js +52 -0
- package/dist/server/bootstrap.js.map +1 -0
- package/dist/server/embeddings/EmbeddingClient.d.ts +8 -0
- package/dist/server/embeddings/EmbeddingClient.d.ts.map +1 -0
- package/dist/server/embeddings/EmbeddingClient.js +30 -0
- package/dist/server/embeddings/EmbeddingClient.js.map +1 -0
- package/dist/server/embeddings/index.d.ts +5 -0
- package/dist/server/embeddings/index.d.ts.map +1 -0
- package/dist/server/embeddings/index.js +6 -0
- package/dist/server/embeddings/index.js.map +1 -0
- package/dist/server/embeddings/providers/OpenAI.d.ts +3 -0
- package/dist/server/embeddings/providers/OpenAI.d.ts.map +1 -0
- package/dist/server/embeddings/providers/OpenAI.js +15 -0
- package/dist/server/embeddings/providers/OpenAI.js.map +1 -0
- package/dist/server/embeddings/registry.d.ts +7 -0
- package/dist/server/embeddings/registry.d.ts.map +1 -0
- package/dist/server/embeddings/registry.js +15 -0
- package/dist/server/embeddings/registry.js.map +1 -0
- package/dist/server/embeddings/types.d.ts +11 -0
- package/dist/server/embeddings/types.d.ts.map +1 -0
- package/dist/server/embeddings/types.js +2 -0
- package/dist/server/embeddings/types.js.map +1 -0
- package/dist/server/index.d.ts +71 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +46 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/uglyBotProxy.d.ts +2 -0
- package/dist/server/uglyBotProxy.d.ts.map +1 -0
- package/dist/server/uglyBotProxy.js +39 -0
- package/dist/server/uglyBotProxy.js.map +1 -0
- package/dist/server/vector.d.ts +58 -0
- package/dist/server/vector.d.ts.map +1 -0
- package/dist/server/vector.js +300 -0
- package/dist/server/vector.js.map +1 -0
- package/dist/shared/AiProxy.d.ts +537 -0
- package/dist/shared/AiProxy.d.ts.map +1 -0
- package/dist/shared/AiProxy.js +338 -0
- package/dist/shared/AiProxy.js.map +1 -0
- package/dist/shared/Api.d.ts +125 -0
- package/dist/shared/Api.d.ts.map +1 -0
- package/dist/shared/Api.js +78 -0
- package/dist/shared/Api.js.map +1 -0
- package/dist/shared/Audio.d.ts +262 -0
- package/dist/shared/Audio.d.ts.map +1 -0
- package/dist/shared/Audio.js +82 -0
- package/dist/shared/Audio.js.map +1 -0
- package/dist/shared/DB.d.ts +516 -0
- package/dist/shared/DB.d.ts.map +1 -0
- package/dist/shared/DB.js +140 -0
- package/dist/shared/DB.js.map +1 -0
- package/dist/shared/Defaults.d.ts +15 -0
- package/dist/shared/Defaults.d.ts.map +1 -0
- package/dist/shared/Defaults.js +15 -0
- package/dist/shared/Defaults.js.map +1 -0
- package/dist/shared/Errors.d.ts +10 -0
- package/dist/shared/Errors.d.ts.map +1 -0
- package/dist/shared/Errors.js +19 -0
- package/dist/shared/Errors.js.map +1 -0
- package/dist/shared/EventCounter.d.ts +32 -0
- package/dist/shared/EventCounter.d.ts.map +1 -0
- package/dist/shared/EventCounter.js +3 -0
- package/dist/shared/EventCounter.js.map +1 -0
- package/dist/shared/Experiment.d.ts +23 -0
- package/dist/shared/Experiment.d.ts.map +1 -0
- package/dist/shared/Experiment.js +34 -0
- package/dist/shared/Experiment.js.map +1 -0
- package/dist/shared/FeedbackReport.d.ts +57 -0
- package/dist/shared/FeedbackReport.d.ts.map +1 -0
- package/dist/shared/FeedbackReport.js +22 -0
- package/dist/shared/FeedbackReport.js.map +1 -0
- package/dist/shared/FrameworkMessages.d.ts +9 -0
- package/dist/shared/FrameworkMessages.d.ts.map +1 -0
- package/dist/shared/FrameworkMessages.js +8 -0
- package/dist/shared/FrameworkMessages.js.map +1 -0
- package/dist/shared/FrameworkRequests.d.ts +156 -0
- package/dist/shared/FrameworkRequests.d.ts.map +1 -0
- package/dist/shared/FrameworkRequests.js +195 -0
- package/dist/shared/FrameworkRequests.js.map +1 -0
- package/dist/shared/ImageGen.d.ts +101 -0
- package/dist/shared/ImageGen.d.ts.map +1 -0
- package/dist/shared/ImageGen.js +119 -0
- package/dist/shared/ImageGen.js.map +1 -0
- package/dist/shared/InboundEmail.d.ts +17 -0
- package/dist/shared/InboundEmail.d.ts.map +1 -0
- package/dist/shared/InboundEmail.js +2 -0
- package/dist/shared/InboundEmail.js.map +1 -0
- package/dist/shared/Router.d.ts +39 -0
- package/dist/shared/Router.d.ts.map +1 -0
- package/dist/shared/Router.js +82 -0
- package/dist/shared/Router.js.map +1 -0
- package/dist/shared/SchemaDiff.d.ts +17 -0
- package/dist/shared/SchemaDiff.d.ts.map +1 -0
- package/dist/shared/SchemaDiff.js +146 -0
- package/dist/shared/SchemaDiff.js.map +1 -0
- package/dist/shared/SchemaSerializer.d.ts +30 -0
- package/dist/shared/SchemaSerializer.d.ts.map +1 -0
- package/dist/shared/SchemaSerializer.js +110 -0
- package/dist/shared/SchemaSerializer.js.map +1 -0
- package/dist/shared/Socket.d.ts +65 -0
- package/dist/shared/Socket.d.ts.map +1 -0
- package/dist/shared/Socket.js +2 -0
- package/dist/shared/Socket.js.map +1 -0
- package/dist/shared/Strings.d.ts +88 -0
- package/dist/shared/Strings.d.ts.map +1 -0
- package/dist/shared/Strings.js +79 -0
- package/dist/shared/Strings.js.map +1 -0
- package/dist/shared/TextGen.d.ts +629 -0
- package/dist/shared/TextGen.d.ts.map +1 -0
- package/dist/shared/TextGen.js +1094 -0
- package/dist/shared/TextGen.js.map +1 -0
- package/dist/shared/UglyBotMessages.d.ts +21 -0
- package/dist/shared/UglyBotMessages.d.ts.map +1 -0
- package/dist/shared/UglyBotMessages.js +22 -0
- package/dist/shared/UglyBotMessages.js.map +1 -0
- package/dist/shared/Voice.d.ts +66 -0
- package/dist/shared/Voice.d.ts.map +1 -0
- package/dist/shared/Voice.js +18 -0
- package/dist/shared/Voice.js.map +1 -0
- package/dist/shared/WebSearch.d.ts +27 -0
- package/dist/shared/WebSearch.d.ts.map +1 -0
- package/dist/shared/WebSearch.js +3 -0
- package/dist/shared/WebSearch.js.map +1 -0
- package/dist/shared/index.d.ts +53 -0
- package/dist/shared/index.d.ts.map +1 -0
- package/dist/shared/index.js +76 -0
- package/dist/shared/index.js.map +1 -0
- package/dist/shared/lang/builtin_en.d.ts +4 -0
- package/dist/shared/lang/builtin_en.d.ts.map +1 -0
- package/dist/shared/lang/builtin_en.js +27 -0
- package/dist/shared/lang/builtin_en.js.map +1 -0
- package/dist/shared/uglyBotUrl.d.ts +7 -0
- package/dist/shared/uglyBotUrl.d.ts.map +1 -0
- package/dist/shared/uglyBotUrl.js +19 -0
- package/dist/shared/uglyBotUrl.js.map +1 -0
- package/dist/three/client/index.d.ts +3 -0
- package/dist/three/client/index.d.ts.map +1 -0
- package/dist/three/client/index.js +5 -0
- package/dist/three/client/index.js.map +1 -0
- package/dist/three/server/VideoEncoder.d.ts +132 -0
- package/dist/three/server/VideoEncoder.d.ts.map +1 -0
- package/dist/three/server/VideoEncoder.js +514 -0
- package/dist/three/server/VideoEncoder.js.map +1 -0
- package/dist/three/server/index.d.ts +5 -0
- package/dist/three/server/index.d.ts.map +1 -0
- package/dist/three/server/index.js +6 -0
- package/dist/three/server/index.js.map +1 -0
- package/dist/three/shared/CameraController.d.ts +89 -0
- package/dist/three/shared/CameraController.d.ts.map +1 -0
- package/dist/three/shared/CameraController.js +341 -0
- package/dist/three/shared/CameraController.js.map +1 -0
- package/dist/three/shared/HeadlessEnvironment.d.ts +87 -0
- package/dist/three/shared/HeadlessEnvironment.d.ts.map +1 -0
- package/dist/three/shared/HeadlessEnvironment.js +647 -0
- package/dist/three/shared/HeadlessEnvironment.js.map +1 -0
- package/dist/three/shared/PostProcessing.d.ts +65 -0
- package/dist/three/shared/PostProcessing.d.ts.map +1 -0
- package/dist/three/shared/PostProcessing.js +491 -0
- package/dist/three/shared/PostProcessing.js.map +1 -0
- package/dist/vite/dataSourcePlugin.d.ts +8 -0
- package/dist/vite/dataSourcePlugin.d.ts.map +1 -0
- package/dist/vite/dataSourcePlugin.js +55 -0
- package/dist/vite/dataSourcePlugin.js.map +1 -0
- package/dist/vite/index.d.ts +3 -0
- package/dist/vite/index.d.ts.map +1 -0
- package/dist/vite/index.js +3 -0
- package/dist/vite/index.js.map +1 -0
- package/dist/vite/tunnelPlugin.d.ts +10 -0
- package/dist/vite/tunnelPlugin.d.ts.map +1 -0
- package/dist/vite/tunnelPlugin.js +30 -0
- package/dist/vite/tunnelPlugin.js.map +1 -0
- package/dist/webrtc/index.d.ts +14 -0
- package/dist/webrtc/index.d.ts.map +1 -0
- package/dist/webrtc/index.js +24 -0
- package/dist/webrtc/index.js.map +1 -0
- package/dist/webrtc/server/VideoRoomServer.d.ts +109 -0
- package/dist/webrtc/server/VideoRoomServer.d.ts.map +1 -0
- package/dist/webrtc/server/VideoRoomServer.js +469 -0
- package/dist/webrtc/server/VideoRoomServer.js.map +1 -0
- package/dist/webrtc/server/index.d.ts +21 -0
- package/dist/webrtc/server/index.d.ts.map +1 -0
- package/dist/webrtc/server/index.js +24 -0
- package/dist/webrtc/server/index.js.map +1 -0
- package/dist/worker/TaskContext.d.ts +59 -0
- package/dist/worker/TaskContext.d.ts.map +1 -0
- package/dist/worker/TaskContext.js +2 -0
- package/dist/worker/TaskContext.js.map +1 -0
- package/dist/worker/TaskHost.d.ts +74 -0
- package/dist/worker/TaskHost.d.ts.map +1 -0
- package/dist/worker/TaskHost.js +187 -0
- package/dist/worker/TaskHost.js.map +1 -0
- package/dist/worker/index.d.ts +3 -0
- package/dist/worker/index.d.ts.map +1 -0
- package/dist/worker/index.js +2 -0
- package/dist/worker/index.js.map +1 -0
- package/package.json +1 -1
- package/src/cli/version.ts +1 -1
- package/ugly-app-0.1.463.tgz +0 -0
package/README.md
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
# ugly-app
|
|
2
2
|
|
|
3
|
-
A full-stack TypeScript framework for
|
|
3
|
+
A full-stack TypeScript framework for shipping production web apps with one CLI. Scaffold with `npx ugly-app init my-app` and get an opinionated Express + React + PostgreSQL stack with built-in auth, type-safe RPC over WebSocket and HTTP, real-time document tracking, AI generation, storage, and a CLI for every workflow.
|
|
4
|
+
|
|
5
|
+
ugly-app is designed to be deployed and operated through [ugly.bot](https://ugly.bot) — the platform handles auth, infra (PostgreSQL, Qdrant, NATS, S3-compatible object storage), AI provider keys, and deployment. Your app talks to all of this through the project's dev tunnel and the per-app `UGLY_BOT_TOKEN`.
|
|
4
6
|
|
|
5
7
|
## What's included
|
|
6
8
|
|
|
7
9
|
- **Server**: Express + WebSocket with type-safe RPC and Zod validation
|
|
8
|
-
- **Client**: React + Vite with typed routing, lazy pages,
|
|
9
|
-
- **Database**:
|
|
10
|
-
- **Auth**:
|
|
11
|
-
- **AI**: Text
|
|
12
|
-
- **
|
|
13
|
-
- **
|
|
14
|
-
- **
|
|
15
|
-
- **
|
|
10
|
+
- **Client**: React + Vite with typed routing, lazy pages, animated transitions, popup management
|
|
11
|
+
- **Database**: PostgreSQL (JSONB) via the data proxy, with full-text search (`search`) and vector search (Qdrant `vector`)
|
|
12
|
+
- **Auth**: HttpOnly cookies + JWT, ugly.bot OAuth out of the box, extensible via `AuthProvider`
|
|
13
|
+
- **AI**: Text, image, embeddings, web search — all proxied through ugly.bot (no per-provider keys in your app)
|
|
14
|
+
- **Realtime**: NATS pub/sub and document change subscriptions (`trackDoc` / `trackDocs`)
|
|
15
|
+
- **Storage**: S3-compatible buckets with presigned uploads
|
|
16
|
+
- **Workers & cron**: `setWorkers()` registers named async tasks with optional Zod input schemas and cron schedules
|
|
17
|
+
- **Localization**: Strings tables with critical-string SSR injection
|
|
18
|
+
- **Experiments**: Deterministic A/B bucketing tied to event logging
|
|
19
|
+
- **CLI**: `ugly-app` commands for dev, build, deploy, migrations, logs, AI, and auth
|
|
16
20
|
|
|
17
21
|
## Quick start
|
|
18
22
|
|
|
@@ -22,112 +26,127 @@ cd my-app
|
|
|
22
26
|
npm run dev
|
|
23
27
|
```
|
|
24
28
|
|
|
29
|
+
The scaffold gives you a working app at `http://localhost:4321` with todo CRUD, AI chat, file upload, auth demo, collab editing, and ~20 other test pages wired up.
|
|
30
|
+
|
|
25
31
|
---
|
|
26
32
|
|
|
27
33
|
## Server
|
|
28
34
|
|
|
29
35
|
### `createApp()`
|
|
30
36
|
|
|
31
|
-
|
|
37
|
+
The single server entry point. Returns an `App` that owns Express, the WebSocket server, the typed DB, and the RPC dispatcher.
|
|
32
38
|
|
|
33
39
|
```typescript
|
|
34
40
|
import {
|
|
35
41
|
createApp,
|
|
36
|
-
createUserHelper,
|
|
37
|
-
getFeedbackHandlers,
|
|
38
42
|
type AppConfigurator,
|
|
39
43
|
type RequestHandlers,
|
|
40
44
|
} from 'ugly-app';
|
|
41
45
|
import { dbDefaults } from 'ugly-app/shared';
|
|
42
|
-
import { requests } from '../shared/api';
|
|
46
|
+
import { requests, messages } from '../shared/api';
|
|
43
47
|
import { collections } from '../shared/collections';
|
|
44
48
|
import { pages } from '../shared/pages';
|
|
45
|
-
import type { User } from '../shared/collections';
|
|
46
|
-
|
|
47
|
-
const userHelper = createUserHelper<User>(collections.user);
|
|
48
|
-
const maintainBotUserId = process.env.MAINTAIN_BOT_USER_ID ?? '';
|
|
49
49
|
|
|
50
50
|
const app = createApp(
|
|
51
|
-
{ requests },
|
|
51
|
+
{ requests, messages },
|
|
52
52
|
{
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
return {
|
|
53
|
+
createTodo: async (userId, { text }) => {
|
|
54
|
+
const _id = crypto.randomUUID();
|
|
55
|
+
await app.db.setDoc(collections.todo, { _id, userId, text, done: false, ...dbDefaults() });
|
|
56
|
+
return { id: _id };
|
|
57
57
|
},
|
|
58
58
|
} satisfies RequestHandlers<typeof requests>,
|
|
59
59
|
collections,
|
|
60
60
|
(configurator: AppConfigurator) => {
|
|
61
61
|
configurator.setPages({ pages });
|
|
62
|
-
configurator.setUserHelper(userHelper);
|
|
63
|
-
configurator.setOnUserCreate(async (userId, info, db) => {
|
|
64
|
-
await userHelper.set(db, { id: userId, ...dbDefaults(), ...info });
|
|
65
|
-
});
|
|
66
62
|
},
|
|
67
63
|
);
|
|
68
64
|
|
|
69
|
-
|
|
70
|
-
await app.start(port);
|
|
65
|
+
await app.start(parseInt(process.env['PORT'] ?? '4321'));
|
|
71
66
|
```
|
|
72
67
|
|
|
73
68
|
**Signature:**
|
|
74
69
|
|
|
75
70
|
```typescript
|
|
76
71
|
function createApp<R extends AppRegistryBase, Defs extends CollectionDefRegistry>(
|
|
77
|
-
registry: R,
|
|
78
|
-
requests: Partial<RequestHandlers<R['requests']>>,
|
|
79
|
-
appDefs: Defs,
|
|
80
|
-
configure?: (
|
|
81
|
-
|
|
72
|
+
registry: R, // { requests, messages }
|
|
73
|
+
requests: Partial<RequestHandlers<R['requests']>>, // handler implementations
|
|
74
|
+
appDefs: Defs, // collections from defineCollections()
|
|
75
|
+
configure?: (c: AppConfigurator) => void,
|
|
76
|
+
deleteHandlers?: DeleteHandlers<Defs>, // per-collection onDelete hooks
|
|
77
|
+
): App<CollectionMap<typeof BUILTIN_DEFS & Defs>>;
|
|
82
78
|
```
|
|
83
79
|
|
|
84
80
|
The returned `App` object has:
|
|
85
|
-
- `start(port?)` —
|
|
86
|
-
- `
|
|
87
|
-
- `httpServer` — the underlying Node.
|
|
88
|
-
- `
|
|
89
|
-
- `wss` — the main `WebSocketServer` instance (path configured via `setWsPath`, default `'/rpc'`)
|
|
81
|
+
- `start(port?)` — start the server (default port 3000; templates use 4321)
|
|
82
|
+
- `db` — the `TypedDB` instance, also available globally via imports
|
|
83
|
+
- `httpServer` — the underlying Node `http.Server`
|
|
84
|
+
- `wss` — the main `WebSocketServer` (path set by `setWsPath`, default `/rpc`)
|
|
90
85
|
- `dispatch(name, input, userId)` — invoke an RPC handler programmatically
|
|
86
|
+
- `registerRoutes(fn)` — mount more Express routes after creation
|
|
87
|
+
|
|
88
|
+
Framework-managed background services start automatically: schema drift check, NATS connection + KV buckets (`TTS`, `RATELIMIT`), data-proxy connection, event counter flush, TTL cleanup for log tables, console / error capture, and ugly.bot log forwarding.
|
|
91
89
|
|
|
92
90
|
### `AppConfigurator`
|
|
93
91
|
|
|
94
|
-
|
|
92
|
+
Passed to the optional fourth argument of `createApp`. Every method is optional.
|
|
95
93
|
|
|
96
94
|
| Method | Description |
|
|
97
95
|
|--------|-------------|
|
|
98
|
-
| `setPages(
|
|
99
|
-
| `setUserHelper(helper)` |
|
|
100
|
-
| `setOnUserCreate(handler)` | Called on first login
|
|
101
|
-
| `setAuth(provider)` |
|
|
102
|
-
| `setOnSocketMessage(handler)` |
|
|
103
|
-
| `
|
|
104
|
-
| `
|
|
105
|
-
| `
|
|
106
|
-
| `
|
|
107
|
-
| `
|
|
108
|
-
| `
|
|
109
|
-
| `
|
|
110
|
-
| `
|
|
96
|
+
| `setPages({ pages, renderPage?, clientDistPath? })` | Mount the SPA. In dev, runs Vite in middleware mode; in prod, serves `dist/client`. Provide `renderPage` for SSR on pages with `ssr: true`. |
|
|
97
|
+
| `setUserHelper(helper)` | Customize how the framework reads / writes the `user` collection during WebSocket auth (default looks up by id in a generic `user` collection). |
|
|
98
|
+
| `setOnUserCreate(handler)` | Called on first login with `(userId, { email?, phone? }, db)` — your chance to create the user record. |
|
|
99
|
+
| `setAuth(provider)` | Replace the default ugly.bot OAuth provider. Must implement `verify(code)` and `authUrl(origin)`. |
|
|
100
|
+
| `setOnSocketMessage(handler)` | Single raw-WebSocket message handler. Return `true` to consume, `false` to fall through. |
|
|
101
|
+
| `addSocketMessageHandler(handler)` | Append to the handler chain; first to return `true` wins. |
|
|
102
|
+
| `setWsPath(path)` | Override the WebSocket path (default `/rpc`). |
|
|
103
|
+
| `setOnWsAuth(handler)` | `(ws, userId, req) => void` — fires after a socket session authenticates. |
|
|
104
|
+
| `setOnAfterStart(handler)` | `(db) => Promise<void>` — called once after data-proxy + NATS are ready. |
|
|
105
|
+
| `setOnMinuteTick(fn)` / `setOnHourlyTick(fn)` | Framework-managed periodic callbacks. Only fire when `CLOCK_ENABLED=true`. |
|
|
106
|
+
| `setHealthHandler(fn)` | Override the default `GET /health` response. |
|
|
107
|
+
| `setExperiments(experiments)` | Register `Experiment` definitions for `initSession` / `captureEvent` bucketing. |
|
|
108
|
+
| `setOnEmail(handler)` | Handle inbound emails routed to `{domain}@ugly.bot` (called via internal HTTP). |
|
|
109
|
+
| `setCronTasks(tasks, handlers)` | Legacy cron-only registry. Prefer `setWorkers()`. |
|
|
110
|
+
| `setWorkers(workers, handlers)` | Register named async tasks with optional Zod input schema and cron schedule. Powers `/_workers/manifest`, `POST /_workers/run`, and the cron orchestrator. |
|
|
111
|
+
| `setStrings(config)` | Localization config — framework injects language + critical strings into SSR HTML and exposes `resolveLanguage` / `getCriticalStrings`. |
|
|
112
|
+
| `registerRoutes(fn)` | Mount custom Express routes. |
|
|
113
|
+
| `setWorkerQueue(queue)` | Register a `WorkerQueue` with `start()` / `stop()` for app lifecycle management. |
|
|
111
114
|
|
|
112
115
|
### Handler signatures
|
|
113
116
|
|
|
114
|
-
Handlers are plain async functions — no context object
|
|
117
|
+
Handlers are plain async functions — no context object:
|
|
115
118
|
|
|
116
119
|
```typescript
|
|
117
120
|
// req() — public, userId may be null
|
|
118
121
|
getPublicData: async (userId: string | null, input) => { ... }
|
|
119
122
|
|
|
120
|
-
// authReq() — authenticated,
|
|
123
|
+
// authReq() — authenticated, framework returns 401 if no/invalid token
|
|
121
124
|
getMe: async (userId: string, input) => { ... }
|
|
122
125
|
```
|
|
123
126
|
|
|
124
|
-
|
|
127
|
+
Inside a handler, access state via captured imports — `app.db`, `storage`, `pgQuery`, `uglyBotRequest`, etc. There is no injected context.
|
|
128
|
+
|
|
129
|
+
### Built-in framework requests
|
|
130
|
+
|
|
131
|
+
`createApp` automatically registers several framework handlers, accessible from any client via the normal RPC pipeline:
|
|
132
|
+
|
|
133
|
+
| Name | Purpose |
|
|
134
|
+
|------|---------|
|
|
135
|
+
| `userGet` | Returns `{ userId, name, avatarUri }` for the given user (or caller). |
|
|
136
|
+
| `initSession` | Records a session start, returns experiment branch assignments. |
|
|
137
|
+
| `captureEvent` | Records a client event tied to the session and experiment branches. |
|
|
138
|
+
| `textGen` / `imageGen` | AI proxies — server-validated, billed through ugly.bot. |
|
|
139
|
+
| `kagiSearch` / `kagiSummarize` / `kagiEnrichWeb` / `kagiEnrichNews` | Web search via ugly.bot. |
|
|
140
|
+
| `uploadUrl` | Issues a presigned PUT for the `temp` bucket. |
|
|
141
|
+
| `submitFeedbackBot` | Forwards `db.captureFeedback` writes for the maintain-bot persona. |
|
|
142
|
+
|
|
143
|
+
App-provided handlers with the same name override the framework's defaults.
|
|
125
144
|
|
|
126
145
|
---
|
|
127
146
|
|
|
128
147
|
## Shared API definitions
|
|
129
148
|
|
|
130
|
-
|
|
149
|
+
`shared/` is consumed by both server and client. Keep all Zod schemas, types, collections, and route declarations here.
|
|
131
150
|
|
|
132
151
|
### Requests (`shared/api.ts`)
|
|
133
152
|
|
|
@@ -135,19 +154,19 @@ All type definitions live in `shared/` and are used by both server and client.
|
|
|
135
154
|
import { authReq, defineRequests, req, z } from 'ugly-app/shared';
|
|
136
155
|
|
|
137
156
|
export const requests = defineRequests({
|
|
138
|
-
// Public
|
|
157
|
+
// Public — handler signature: (userId: string | null, input) => Promise<output>
|
|
139
158
|
getPublicData: req({
|
|
140
159
|
input: z.object({ id: z.string() }),
|
|
141
160
|
output: z.object({ data: z.string() }),
|
|
142
161
|
}),
|
|
143
162
|
|
|
144
|
-
// Authenticated
|
|
163
|
+
// Authenticated — 401 enforced automatically, userId guaranteed string
|
|
145
164
|
getMe: authReq({
|
|
146
165
|
input: z.object({}),
|
|
147
166
|
output: z.object({ userId: z.string(), email: z.string().optional() }),
|
|
148
167
|
}),
|
|
149
168
|
|
|
150
|
-
// With rate limiting
|
|
169
|
+
// With per-endpoint rate limiting (enforced before handler runs)
|
|
151
170
|
submitFeedback: authReq({
|
|
152
171
|
input: z.object({ type: z.enum(['bug', 'design', 'feature']), message: z.string() }),
|
|
153
172
|
output: z.object({ id: z.string() }),
|
|
@@ -156,42 +175,41 @@ export const requests = defineRequests({
|
|
|
156
175
|
});
|
|
157
176
|
```
|
|
158
177
|
|
|
159
|
-
|
|
160
|
-
- `authReq({ input, output })` — defines an authenticated request. Handler signature: `(userId: string, input: I) => Promise<O>`. Returns 401 automatically if no token.
|
|
161
|
-
- `defineRequests()` — identity wrapper that preserves types.
|
|
162
|
-
- `z` is re-exported from Zod for convenience.
|
|
163
|
-
|
|
164
|
-
Every endpoint is accessible via both WebSocket (`socket.request(name, input)`) and HTTP (`POST /api/:name { input }`).
|
|
178
|
+
Every request is reachable as **both** `socket.request(name, input)` (WebSocket) and `POST /api/:name { input }` (HTTP). `z` is re-exported from Zod for convenience.
|
|
165
179
|
|
|
166
180
|
### Collections (`shared/collections.ts`)
|
|
167
181
|
|
|
168
182
|
```typescript
|
|
169
|
-
import { defineCollections } from 'ugly-app/shared';
|
|
170
|
-
import
|
|
183
|
+
import { defineCollections, InferDocType } from 'ugly-app/shared';
|
|
184
|
+
import { z } from 'zod';
|
|
185
|
+
|
|
186
|
+
export const TodoSchema = z.object({
|
|
187
|
+
userId: z.string(),
|
|
188
|
+
text: z.string(),
|
|
189
|
+
done: z.boolean(),
|
|
190
|
+
});
|
|
191
|
+
export type Todo = InferDocType<typeof TodoSchema>;
|
|
171
192
|
|
|
172
193
|
export const collections = defineCollections({
|
|
173
|
-
|
|
174
|
-
|
|
194
|
+
todo: {
|
|
195
|
+
schema: TodoSchema,
|
|
175
196
|
meta: { cache: true, trackable: true, public: false, cascadeFrom: null },
|
|
176
197
|
},
|
|
177
|
-
user: {
|
|
178
|
-
type: {} as User,
|
|
179
|
-
meta: { cache: true, trackable: false, public: false, cascadeFrom: null },
|
|
180
|
-
},
|
|
181
198
|
});
|
|
182
199
|
```
|
|
183
200
|
|
|
184
|
-
|
|
185
|
-
- `
|
|
186
|
-
- `
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
201
|
+
`CollectionMeta`:
|
|
202
|
+
- `cache` — read `getDoc` through an LRU cache; writes invalidate it.
|
|
203
|
+
- `trackable` — enables real-time `trackDoc` / `trackDocs` via NATS.
|
|
204
|
+
- `public` — allow unauthenticated client reads.
|
|
205
|
+
- `cascadeFrom` — parent collection for cascade deletes.
|
|
206
|
+
- `trackKeys?` — fields usable as NATS routing keys for `trackDocs`.
|
|
207
|
+
- `search?: { fields, language? }` — PostgreSQL full-text search columns.
|
|
208
|
+
- `vector?: { dimensions, source }` — Qdrant vector index over the named JSONB path.
|
|
209
|
+
|
|
210
|
+
All documents extend `DBObject`: `{ _id, version, created, updated }`. Use `dbDefaults()` to stamp the latter three on inserts.
|
|
193
211
|
|
|
194
|
-
|
|
212
|
+
After schema changes, run `npm run db:schema-gen` and then `npm run db:migrate`. The app refuses to start when drift is detected (set `SCHEMA_CHECK_SKIP=true` only as a last resort).
|
|
195
213
|
|
|
196
214
|
### Pages (`shared/pages.ts`)
|
|
197
215
|
|
|
@@ -199,922 +217,513 @@ All documents extend `DBObject`: `{ _id: string, version: number, created: Date,
|
|
|
199
217
|
import { definePage, definePages } from 'ugly-app/shared';
|
|
200
218
|
|
|
201
219
|
export const pages = definePages({
|
|
202
|
-
'': definePage<{}>({ auth: false }),
|
|
203
|
-
'
|
|
204
|
-
'search': definePage<{ q?: string }>({ auth: false })
|
|
205
|
-
'blog/*slug': definePage<{ slug: string }>({ ssr: true })
|
|
220
|
+
'': definePage<{}>({ auth: false }), // /
|
|
221
|
+
'user/:userId': definePage<{ userId: string }>(), // /user/abc
|
|
222
|
+
'search': definePage<{ q?: string }>({ auth: false }), // /search?q=foo
|
|
223
|
+
'blog/*slug': definePage<{ slug: string }>({ ssr: true }), // /blog/any/path
|
|
206
224
|
});
|
|
207
225
|
export type AppPages = typeof pages;
|
|
208
226
|
```
|
|
209
227
|
|
|
210
|
-
- `:param`
|
|
211
|
-
-
|
|
212
|
-
- `
|
|
213
|
-
-
|
|
228
|
+
- `:param` matches a single path segment; `*param` is greedy (captures slashes).
|
|
229
|
+
- The generic on `definePage<Params>()` is **phantom** — never set at runtime, used for client-side type inference.
|
|
230
|
+
- `auth` defaults to `true`. `ssr` defaults to `false`.
|
|
231
|
+
- Query-string params are declared in `Params` but never appear in the path template.
|
|
214
232
|
|
|
215
233
|
---
|
|
216
234
|
|
|
217
235
|
## Client
|
|
218
236
|
|
|
219
|
-
###
|
|
220
|
-
|
|
221
|
-
```tsx
|
|
222
|
-
import { createRoot } from 'react-dom/client';
|
|
223
|
-
import { AppProvider, createSocket, LoginPopup } from 'ugly-app/client';
|
|
224
|
-
import { requests } from '../shared/api';
|
|
225
|
-
import { RouterProvider } from './router';
|
|
226
|
-
import App from './App';
|
|
227
|
-
|
|
228
|
-
const token = (window as unknown as { __AUTH_TOKEN__?: string }).__AUTH_TOKEN__;
|
|
229
|
-
const root = createRoot(document.getElementById('root')!);
|
|
230
|
-
const loginPopup = <LoginPopup onSuccess={() => window.location.reload()} />;
|
|
231
|
-
|
|
232
|
-
if (!token) {
|
|
233
|
-
root.render(
|
|
234
|
-
<RouterProvider fallback={<div>404</div>} loginFallback={loginPopup} isAuthenticated={() => false}>
|
|
235
|
-
<App socket={null} />
|
|
236
|
-
</RouterProvider>,
|
|
237
|
-
);
|
|
238
|
-
} else {
|
|
239
|
-
const userId = JSON.parse(atob(token.split('.')[1]!)).sub as string;
|
|
240
|
-
const socket = createSocket({ requests, url: '/rpc' });
|
|
241
|
-
socket.connect(token).then((user) => {
|
|
242
|
-
root.render(
|
|
243
|
-
<RouterProvider fallback={<div>404</div>} loginFallback={loginPopup} isAuthenticated={() => true}>
|
|
244
|
-
<AppProvider socket={socket} userId={userId} user={user}>
|
|
245
|
-
<App socket={socket} />
|
|
246
|
-
</AppProvider>
|
|
247
|
-
</RouterProvider>,
|
|
248
|
-
);
|
|
249
|
-
});
|
|
250
|
-
}
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
### `createSocket()`
|
|
254
|
-
|
|
255
|
-
Creates a typed WebSocket client for RPC communication.
|
|
256
|
-
|
|
257
|
-
```typescript
|
|
258
|
-
const socket = createSocket({ requests, url: '/rpc' });
|
|
259
|
-
await socket.connect(token); // returns UserBase
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
**`AppSocket` methods:**
|
|
263
|
-
|
|
264
|
-
| Method | Description |
|
|
265
|
-
|--------|-------------|
|
|
266
|
-
| `connect(token)` | Authenticate and connect. Returns the user object |
|
|
267
|
-
| `request(name, input)` | Invoke a typed request (query or mutation) |
|
|
268
|
-
| `getDoc(collection, id)` | Fetch a single document |
|
|
269
|
-
| `getDocs(collection, filter?, opts?)` | Query documents (filter, sort, limit, skip) |
|
|
270
|
-
| `getQuery(collection, pipeline, opts?)` | Run an aggregation pipeline |
|
|
271
|
-
| `trackDoc(collection, id, cb)` | Subscribe to real-time doc changes. Returns unsubscribe fn |
|
|
272
|
-
| `trackDocs(collection, params, cb)` | Subscribe to query results (`keys`, `filter`, `sort`, `limit`, `skip`). Returns unsubscribe fn |
|
|
273
|
-
| `uploadFile(file, key)` | Upload a file via presigned URL |
|
|
274
|
-
| `emit(type, data)` | Send a fire-and-forget message over WebSocket |
|
|
275
|
-
| `send(type, data, timeout?)` | Send a message and wait for a response |
|
|
276
|
-
| `waitForConnection(timeout?)` | Wait until the socket is connected |
|
|
277
|
-
| `connectionState` | Current state: `'connecting'` \| `'connected'` \| `'reconnecting'` \| `'disconnected'` \| `'idle-disconnected'` |
|
|
278
|
-
| `disconnect()` | Close the connection |
|
|
279
|
-
|
|
280
|
-
**`createSocket()` options:**
|
|
281
|
-
|
|
282
|
-
| Option | Description |
|
|
283
|
-
|--------|-------------|
|
|
284
|
-
| `requests` | The requests registry from `shared/api.ts` |
|
|
285
|
-
| `url?` | WebSocket path (default: `'/rpc'`) |
|
|
286
|
-
| `buildId?` | Build identifier sent on connect |
|
|
287
|
-
| `onCustomMessage?` | Handle custom server-pushed messages |
|
|
288
|
-
| `getUrlParams?` | Extra query params appended to the WebSocket URL |
|
|
289
|
-
| `messageReviver?` | JSON reviver for incoming messages (e.g. Date parsing) |
|
|
290
|
-
|
|
291
|
-
### `createHttpClient()`
|
|
292
|
-
|
|
293
|
-
Creates a typed HTTP client for RPC communication (no WebSocket needed).
|
|
294
|
-
|
|
295
|
-
```typescript
|
|
296
|
-
import { createHttpClient } from 'ugly-app/client';
|
|
297
|
-
|
|
298
|
-
const client = createHttpClient({ requests, token: 'eyJ...', baseUrl: '' });
|
|
299
|
-
const result = await client.request('getMe', {});
|
|
300
|
-
```
|
|
301
|
-
|
|
302
|
-
| Option | Description |
|
|
303
|
-
|--------|-------------|
|
|
304
|
-
| `requests` | The requests registry from `shared/api.ts` |
|
|
305
|
-
| `token?` | Bearer token for authenticated requests |
|
|
306
|
-
| `baseUrl?` | URL prefix (default: `''` — relative paths: `POST /api/:name`) |
|
|
237
|
+
### `bootstrapApp()`
|
|
307
238
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
Wraps your app with context for `useApp()`. Provides user info, socket access, popup management, async loading overlay, splash screen, and localization.
|
|
239
|
+
The recommended entrypoint. Handles auth detection, socket creation, optional auto-login through the ugly.bot iframe, and provider wiring.
|
|
311
240
|
|
|
312
241
|
```tsx
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
242
|
+
// client/main.tsx
|
|
243
|
+
import { bootstrapApp, FeedbackButton } from 'ugly-app/client';
|
|
244
|
+
import { requests } from '../shared/api';
|
|
245
|
+
import { RouterProvider, RouterView } from './router';
|
|
246
|
+
import './styles.css';
|
|
247
|
+
|
|
248
|
+
bootstrapApp({
|
|
249
|
+
requests,
|
|
250
|
+
RouterProvider,
|
|
251
|
+
render: () => (
|
|
252
|
+
<>
|
|
253
|
+
<RouterView />
|
|
254
|
+
<FeedbackButton />
|
|
255
|
+
</>
|
|
256
|
+
),
|
|
257
|
+
strings: { /* optional StringsProviderConfig */ },
|
|
258
|
+
});
|
|
323
259
|
```
|
|
324
260
|
|
|
325
|
-
|
|
261
|
+
`BootstrapAppOptions`:
|
|
326
262
|
|
|
327
263
|
| Field | Description |
|
|
328
264
|
|-------|-------------|
|
|
329
|
-
| `
|
|
330
|
-
| `
|
|
331
|
-
| `
|
|
332
|
-
| `
|
|
333
|
-
| `
|
|
334
|
-
| `
|
|
335
|
-
| `
|
|
336
|
-
| `
|
|
337
|
-
| `
|
|
338
|
-
|
|
339
|
-
`useAppOptional()` returns the same context or `null` if outside `<AppProvider>`.
|
|
265
|
+
| `requests` | Your `RequestRegistry` (merged with framework requests internally). |
|
|
266
|
+
| `messages?` | Your `MessageRegistry` (merged with framework messages). |
|
|
267
|
+
| `RouterProvider` | The `RouterProvider` returned from `createRouter()`. |
|
|
268
|
+
| `render` | Callback returning the app's UI tree (typically `<RouterView /> + <FeedbackButton />`). |
|
|
269
|
+
| `root?` | Root element / selector (default `'#root'`). |
|
|
270
|
+
| `fallback?` | UI for unmatched routes (default: tiny "404"). |
|
|
271
|
+
| `socketUrl?` | Override the WebSocket path (default `/rpc`). |
|
|
272
|
+
| `strings?` | Localization config — when present, wraps the tree with `<StringsProvider>`. |
|
|
273
|
+
| `keyboard?: false` | Disable the framework `<KeyboardProvider>` wrapper. |
|
|
340
274
|
|
|
341
|
-
`
|
|
275
|
+
`bootstrapApp` reads `window.__AUTH_TOKEN__` (injected by the server). If absent, it renders unauthenticated and lets the router show `loginFallback` for auth-guarded pages. If present, it connects the socket, mounts `<AppProvider>`, and renders.
|
|
342
276
|
|
|
343
|
-
###
|
|
344
|
-
|
|
345
|
-
#### Setup (`client/router.ts`)
|
|
277
|
+
### Routing — `createRouter()`
|
|
346
278
|
|
|
347
279
|
```typescript
|
|
280
|
+
// client/router.ts
|
|
348
281
|
import { createRouter } from 'ugly-app/client';
|
|
349
282
|
import { pages } from '../shared/pages';
|
|
350
283
|
import { allPages } from './allPages';
|
|
351
284
|
|
|
352
|
-
export const { RouterProvider, RouterView, useRouter } = createRouter({
|
|
285
|
+
export const { RouterProvider, RouterView, useRouter } = createRouter({
|
|
286
|
+
pages,
|
|
287
|
+
allPages,
|
|
288
|
+
});
|
|
353
289
|
```
|
|
354
290
|
|
|
355
|
-
`createRouter
|
|
356
|
-
- **`RouterProvider`** — wrap your app. Props: `children`, `fallback?` (shown before first route resolves), `loginFallback?` (shown for auth-guarded pages when unauthenticated), `isAuthenticated?` (function returning boolean)
|
|
357
|
-
- **`RouterView`** — renders the active page with animated transitions. Props: `durationMs?`, `easing?`, `transitionComponent?`, `renderPage?`
|
|
358
|
-
- **`useRouter()`** — hook returning the router context
|
|
291
|
+
`createRouter` returns:
|
|
359
292
|
|
|
360
|
-
|
|
293
|
+
- **`RouterProvider`** — props: `children`, `fallback?`, `loginFallback?`, `isAuthenticated?`, `autoLogin?`. Manages route state, browser history, popups, and `<AutoLoginGate>` (silent iframe-based login check against ugly.bot).
|
|
294
|
+
- **`RouterView`** — renders the active page with animated transitions. Props: `durationMs?`, `easing?`, `transitionComponent?` (replaces `ViewFlipper`), `renderPage?` (sync alternative to `allPages` loaders).
|
|
295
|
+
- **`useRouter()`** — returns the router context (see below).
|
|
296
|
+
|
|
297
|
+
### Page map — `lazyPage` / `lazyPageLoader`
|
|
361
298
|
|
|
362
299
|
```typescript
|
|
300
|
+
// client/allPages.ts
|
|
363
301
|
import { lazyPage, lazyPageLoader } from 'ugly-app/client';
|
|
364
302
|
import type { PageMap } from 'ugly-app/shared';
|
|
365
303
|
import type { AppPages } from '../shared/pages';
|
|
366
304
|
|
|
367
305
|
export const allPages = {
|
|
368
306
|
['']: lazyPage(() => import('./pages/HomePage')),
|
|
369
|
-
['
|
|
370
|
-
['
|
|
371
|
-
['slow']: lazyPageLoader(() => import('./pages/SlowPageLoader')),
|
|
307
|
+
['user/:userId']: lazyPage(() => import('./pages/UserPage')),
|
|
308
|
+
['slow/:id']: lazyPageLoader(() => import('./pages/SlowPageLoader')),
|
|
372
309
|
} satisfies PageMap<AppPages>;
|
|
373
310
|
```
|
|
374
311
|
|
|
375
|
-
- **`lazyPage(factory)`** — lazy-imports a default-exported React
|
|
376
|
-
- **`lazyPageLoader(factory)`** — lazy-imports an async loader
|
|
312
|
+
- **`lazyPage(factory)`** — lazy-imports a default-exported `React.ComponentType<Params>`. The page receives route params as props.
|
|
313
|
+
- **`lazyPageLoader(factory)`** — lazy-imports an async loader `(params) => Promise<ReactElement>`. Use when a route needs data fetching before render. The loader file is the chunk boundary, so it can statically import its page component.
|
|
377
314
|
|
|
378
|
-
|
|
315
|
+
Example loader:
|
|
379
316
|
|
|
380
317
|
```typescript
|
|
381
318
|
// pages/SlowPageLoader.tsx
|
|
382
|
-
import SlowPage from './SlowPage';
|
|
319
|
+
import SlowPage from './SlowPage';
|
|
383
320
|
export default async function PageLoader({ id }: { id: string }) {
|
|
384
321
|
const data = await fetchSlowData(id);
|
|
385
322
|
return <SlowPage {...data} />;
|
|
386
323
|
}
|
|
387
324
|
```
|
|
388
325
|
|
|
389
|
-
|
|
326
|
+
### Navigation — `useRouter()`
|
|
390
327
|
|
|
391
328
|
```typescript
|
|
392
|
-
const { push, replace, back,
|
|
329
|
+
const { current, push, replace, back, openPopup, closePopup, closeAllPopups } = useRouter();
|
|
393
330
|
|
|
394
|
-
push('
|
|
395
|
-
replace('search', { q: 'hello' });
|
|
396
|
-
back();
|
|
331
|
+
push('user/:userId', { userId: '123' }); // → /user/123
|
|
332
|
+
replace('search', { q: 'hello' }); // → /search?q=hello
|
|
333
|
+
back(); // browser history back
|
|
397
334
|
|
|
398
|
-
//
|
|
399
|
-
current.
|
|
400
|
-
current.params; // e.g. { noteId: '123' }
|
|
335
|
+
current.routeName; // typed union of all route keys
|
|
336
|
+
current.params; // typed params for the current route
|
|
401
337
|
```
|
|
402
338
|
|
|
403
|
-
All route names and params are fully typed
|
|
339
|
+
All route names and params are fully typed against `pages`. Internally `push` / `replace` are no-ops when `buildUrl()` produces a URL that doesn't match a registered route (and emit a `console.error`).
|
|
404
340
|
|
|
405
|
-
|
|
341
|
+
### Popups — `openPopup()`
|
|
406
342
|
|
|
407
|
-
Always use `useRouter().openPopup()`
|
|
343
|
+
Always use `useRouter().openPopup()` for modals, sheets, and menus. The router owns the popup layer, manages the spring animation, and stacks popups z-index-correctly.
|
|
408
344
|
|
|
409
345
|
```tsx
|
|
410
346
|
const { openPopup } = useRouter();
|
|
411
347
|
|
|
412
348
|
const handle = openPopup(<MyContent />, {
|
|
413
|
-
mode: 'transient', // 'block' | 'transient' | 'contextMenu'
|
|
414
|
-
slideFrom: 'bottom', // 'left' | 'right' | 'top' | 'bottom' | 'none'
|
|
415
|
-
onClose: () => {},
|
|
416
|
-
containerStyle: {
|
|
417
|
-
backgroundStyle: {
|
|
349
|
+
mode: 'transient', // 'block' (default) | 'transient' | 'contextMenu'
|
|
350
|
+
slideFrom: 'bottom', // 'left' | 'right' | 'top' | 'bottom' | 'none' (default)
|
|
351
|
+
onClose: () => {},
|
|
352
|
+
containerStyle: { /* CSS for the content wrapper */ },
|
|
353
|
+
backgroundStyle: { /* CSS for the backdrop */ },
|
|
418
354
|
animConfig: { duration: 300, easing: myEasingFn },
|
|
419
|
-
renderLayer: (props) => <CustomLayer {...props} />, // fully replace the
|
|
355
|
+
renderLayer: (props) => <CustomLayer {...props} />, // fully replace the layer renderer
|
|
420
356
|
});
|
|
421
357
|
|
|
422
358
|
handle.hide(); // dismiss programmatically
|
|
423
359
|
```
|
|
424
360
|
|
|
425
|
-
|
|
426
|
-
- **`block`** (default) —
|
|
427
|
-
- **`transient`** —
|
|
428
|
-
- **`contextMenu`** — same as transient, intended for menus and pickers
|
|
429
|
-
|
|
430
|
-
`renderLayer` receives `{ content, spring, hide }` — `spring` is an animated value from 0 to 1, `hide` is a function to close the popup.
|
|
361
|
+
Modes:
|
|
362
|
+
- **`block`** (default) — 40% opacity backdrop, **does not** dismiss on backdrop click.
|
|
363
|
+
- **`transient`** — 20% opacity backdrop, **dismisses** on backdrop click.
|
|
364
|
+
- **`contextMenu`** — same as transient, intended for menus and pickers.
|
|
431
365
|
|
|
432
|
-
|
|
366
|
+
`renderLayer` receives `{ content, spring, hide }` — `spring` is an `AnimatedValueRef` driving 0 → 1, `hide` closes the popup.
|
|
433
367
|
|
|
434
|
-
|
|
435
|
-
import { Link } from 'ugly-app/client';
|
|
436
|
-
|
|
437
|
-
<Link router={router} to="note/:noteId" params={{ noteId: '123' }}>
|
|
438
|
-
View Note
|
|
439
|
-
</Link>
|
|
440
|
-
```
|
|
368
|
+
### `AppProvider` & `useApp()`
|
|
441
369
|
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
#### Animation system
|
|
445
|
-
|
|
446
|
-
Built-in animation primitives for transitions and popups. `Animated.div` and `Animated.span` accept `AnimatedStyle` — a style object where any CSS property can be an `AnimatedValueRef` or a `TransformedValue` instead of a static value.
|
|
370
|
+
`bootstrapApp` mounts `<AppProvider>` automatically after socket connect. Use `useApp()` inside any page to access the active user and socket.
|
|
447
371
|
|
|
448
372
|
```typescript
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
//
|
|
460
|
-
|
|
461
|
-
spring.start(1, { duration: 300, easing: easingFunctions.easeOut });
|
|
462
|
-
|
|
463
|
-
// Use in components — animated properties bypass React re-renders via direct DOM mutation
|
|
464
|
-
<Animated.div style={{ opacity: spring.to((v) => String(v)) }}>
|
|
465
|
-
Content
|
|
466
|
-
</Animated.div>
|
|
467
|
-
|
|
468
|
-
// Hook version — creates and manages an animated value in a component
|
|
469
|
-
const anim = useAnimatedValue(0);
|
|
470
|
-
|
|
471
|
-
// Pre-built entrance animations (wrap any children)
|
|
472
|
-
<FadeIn>{children}</FadeIn>
|
|
473
|
-
<SlideFromBottom>{children}</SlideFromBottom>
|
|
474
|
-
<SlideFromRight>{children}</SlideFromRight>
|
|
373
|
+
const {
|
|
374
|
+
userId, // current user id
|
|
375
|
+
user, // UserBase doc
|
|
376
|
+
socket, // AppSocket — typed RPC client
|
|
377
|
+
uglyBotSocket, // optional UglyBotSocket for direct platform calls (STT/TTS, etc.)
|
|
378
|
+
showPopup, // legacy popup API (prefer useRouter().openPopup)
|
|
379
|
+
hidePopup,
|
|
380
|
+
hideAllPopups,
|
|
381
|
+
runAsync, // runAsync('label', async () => { ... }) — shows loading overlay
|
|
382
|
+
splashDone, // mark a splash-screen step complete
|
|
383
|
+
localizer, // (key, params?) => string — alias for useLocalizer
|
|
384
|
+
} = useApp();
|
|
475
385
|
```
|
|
476
386
|
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
| Member | Description |
|
|
480
|
-
|--------|-------------|
|
|
481
|
-
| `current` | Current numeric value |
|
|
482
|
-
| `target` | Target value |
|
|
483
|
-
| `isAnimating` | Whether an animation is in progress |
|
|
484
|
-
| `start(target, config?)` | Animate to target. Returns `Promise<void>` |
|
|
485
|
-
| `set(value)` | Jump to value immediately (no animation) |
|
|
486
|
-
| `stop()` | Cancel the current animation |
|
|
487
|
-
| `subscribe(cb)` | Subscribe to value changes. Returns unsubscribe fn |
|
|
488
|
-
| `to(transform)` | Create a transformed value for use in `Animated` styles |
|
|
489
|
-
|
|
490
|
-
**`AnimConfig`:** `{ duration?, easing?, onRest?, onUpdate?, immediate? }`
|
|
387
|
+
`useAppOptional()` returns `null` outside the provider; `useLocalizer()` returns a localizer that falls back to identity.
|
|
491
388
|
|
|
492
|
-
|
|
389
|
+
### `Link` component
|
|
493
390
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
- `useScrollAnimation` / `useStaggerAnimation` — scroll-driven and staggered entrance animations
|
|
391
|
+
```tsx
|
|
392
|
+
import { Link } from 'ugly-app/client';
|
|
497
393
|
|
|
498
|
-
|
|
394
|
+
<Link router={router} to="user/:userId" params={{ userId: '123' }}>View profile</Link>
|
|
395
|
+
```
|
|
499
396
|
|
|
500
|
-
|
|
501
|
-
import { captureScreenshot } from 'ugly-app/client';
|
|
397
|
+
Renders an `<a>` with the right `href`, intercepts clicks for client-side navigation, and lets `ctrl/cmd+click` open in a new tab.
|
|
502
398
|
|
|
503
|
-
|
|
504
|
-
```
|
|
399
|
+
### Direct socket access
|
|
505
400
|
|
|
506
|
-
|
|
401
|
+
`AppSocket` is exposed through `useApp().socket`. Common methods:
|
|
507
402
|
|
|
508
|
-
|
|
403
|
+
| Method | Description |
|
|
404
|
+
|--------|-------------|
|
|
405
|
+
| `request(name, input)` | Invoke a typed RPC handler. |
|
|
406
|
+
| `getDoc(collection, id)` | Server-mediated doc fetch. |
|
|
407
|
+
| `getDocs(collection, filter?, opts?)` | Filtered query. |
|
|
408
|
+
| `trackDoc(collection, id, cb)` | Live subscription — returns unsubscribe. |
|
|
409
|
+
| `trackDocs(collection, params, cb)` | Live filtered subscription. |
|
|
410
|
+
| `uploadFile(file, key)` | Presigned upload to the `temp` bucket. |
|
|
411
|
+
| `connectionState` | `'connecting' \| 'connected' \| 'reconnecting' \| 'disconnected' \| 'idle-disconnected'`. |
|
|
412
|
+
| `disconnect()` | Close the connection. |
|
|
509
413
|
|
|
510
|
-
|
|
414
|
+
For pure HTTP (no WebSocket), use `createHttpClient({ requests, token?, baseUrl? })`.
|
|
511
415
|
|
|
512
416
|
---
|
|
513
417
|
|
|
514
418
|
## Auth
|
|
515
419
|
|
|
516
|
-
|
|
420
|
+
ugly-app uses HttpOnly cookies and server-side JWT injection — no `localStorage`, no client-side token handling.
|
|
517
421
|
|
|
518
422
|
**Flow:**
|
|
519
423
|
|
|
520
|
-
1.
|
|
521
|
-
2.
|
|
522
|
-
3.
|
|
523
|
-
|
|
524
|
-
<script>window.__AUTH_TOKEN__ = "eyJ..."</script>
|
|
525
|
-
```
|
|
526
|
-
4. Client reads `window.__AUTH_TOKEN__` synchronously and connects the WebSocket
|
|
527
|
-
|
|
528
|
-
**Logout:**
|
|
424
|
+
1. Unauthenticated user lands on a page; the optional `<AutoLoginGate>` opens a hidden iframe to `https://ugly.bot/iframe-auth` to check for an existing platform session.
|
|
425
|
+
2. If found, the iframe posts an OAuth code back; the client POSTs to `/auth/verify`; the server exchanges it through `uglyBotAuthProvider`, sets the `auth_token` HttpOnly cookie, and the page reloads authenticated.
|
|
426
|
+
3. If not found (or timeout after 4 s), `<RouterProvider>` shows `loginFallback` for auth-required routes. The default fallback is `<LoginPopup>`, which opens `https://ugly.bot/oauth` in a popup window.
|
|
427
|
+
4. On every authenticated request, the server verifies the cookie token by calling `${UGLY_BOT_URL}/verify` and injects `window.__AUTH_TOKEN__` into the HTML so the client can pass it on the WebSocket handshake.
|
|
529
428
|
|
|
530
|
-
|
|
531
|
-
await fetch('/auth/logout', { method: 'POST' });
|
|
532
|
-
window.location.reload();
|
|
533
|
-
```
|
|
429
|
+
**Token-in-URL embed mode:** any GET request with `?token=<JWT>` will, if the token verifies against ugly.bot, set the cookie and 302-redirect to the same URL without the token — letting any page be embedded in an iframe.
|
|
534
430
|
|
|
535
|
-
**Built-in
|
|
431
|
+
**Built-in routes** (mounted on every app):
|
|
536
432
|
|
|
537
433
|
| Endpoint | Description |
|
|
538
434
|
|----------|-------------|
|
|
539
|
-
| `POST /auth/verify` | Exchange OAuth code for a session cookie |
|
|
540
|
-
| `POST /auth/logout` | Clear the
|
|
541
|
-
| `GET /auth/token` | Refresh and return the current token |
|
|
542
|
-
| `GET /auth/url` |
|
|
435
|
+
| `POST /auth/verify` | Exchange an OAuth `code` for a session cookie. |
|
|
436
|
+
| `POST /auth/logout` | Clear the cookie. |
|
|
437
|
+
| `GET /auth/token` | Refresh and return the current token (used by clients that need an explicit token). |
|
|
438
|
+
| `GET /auth/url` | Return the OAuth popup URL. |
|
|
543
439
|
|
|
544
|
-
**Custom
|
|
440
|
+
**Custom provider:**
|
|
545
441
|
|
|
546
442
|
```typescript
|
|
547
443
|
configurator.setAuth({
|
|
548
|
-
verify: async (code
|
|
549
|
-
authUrl: (origin
|
|
444
|
+
verify: async (code) => ({ userId: '...', token: 'platform-issued-jwt' }),
|
|
445
|
+
authUrl: (origin) => `https://my-oauth.example/authorize?origin=${origin}`,
|
|
550
446
|
registerRoutes: (router) => { /* optional extra routes */ },
|
|
551
447
|
});
|
|
552
448
|
```
|
|
553
449
|
|
|
554
|
-
|
|
450
|
+
**Server-side helpers** (`ugly-app`):
|
|
555
451
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
verify(code: string): Promise<{ userId: string; email?: string; phone?: string; token?: string }>;
|
|
559
|
-
authUrl(origin: string): string;
|
|
560
|
-
registerRoutes?(router: express.Router): void;
|
|
561
|
-
}
|
|
562
|
-
```
|
|
452
|
+
- `verifyToken(token)` — verifies a token against ugly.bot and returns the `userId`.
|
|
453
|
+
- `getRequestUser(req)` — synchronous decode of the per-project `UGLY_PROJECT_TOKEN` cookie set by ugly.bot's wake-on-traffic gate. Returns `{ userId } | null` without a network round-trip; safe to use as the primary auth check in deployed-app handlers.
|
|
563
454
|
|
|
564
455
|
---
|
|
565
456
|
|
|
566
|
-
## Database
|
|
457
|
+
## Database — `TypedDB`
|
|
567
458
|
|
|
568
|
-
Access via `app.db` or
|
|
569
|
-
|
|
570
|
-
All methods accept either a `CollectionDef` object (from `defineCollections`) or a plain collection name string as the first argument.
|
|
459
|
+
Access via `app.db` or via `import { app } from './your-app-module'`. All methods accept a `CollectionDef` (from `defineCollections`) or a plain collection name string.
|
|
571
460
|
|
|
572
461
|
### Writing
|
|
573
462
|
|
|
574
463
|
```typescript
|
|
575
|
-
|
|
576
|
-
await db.setDoc(collections.note, doc);
|
|
577
|
-
await db.setDoc(collections.note, doc, { skipIfExists: true });
|
|
578
|
-
|
|
579
|
-
// Partial update — only specified fields (supports dot-notation paths)
|
|
580
|
-
await db.setDocFields(collections.note, id, { title: 'New title' });
|
|
464
|
+
await db.setDoc(collections.note, doc); // upsert
|
|
465
|
+
await db.setDoc(collections.note, doc, { skipIfExists: true }); // insert-only
|
|
581
466
|
|
|
582
|
-
|
|
583
|
-
|
|
467
|
+
await db.setDocFields(collections.note, id, { title: 'New' }); // partial; throws if missing
|
|
468
|
+
await db.setDocFieldsOrIgnore(collections.note, id, { title }); // returns null if missing
|
|
469
|
+
await db.setDocFieldsOrCreate(collections.note, id, { title }, default); // upsert with default
|
|
584
470
|
|
|
585
|
-
|
|
586
|
-
await db.
|
|
587
|
-
|
|
588
|
-
// MongoDB update operators ($inc, $addToSet, $pull, $unset, $set)
|
|
589
|
-
await db.setDocOp(collections.note, id, { $inc: { views: 1 } });
|
|
590
|
-
await db.setDocOpOrIgnore(collections.note, id, { $inc: { views: 1 } }); // no error if missing
|
|
471
|
+
await db.setDocOp(collections.note, id, { $inc: { views: 1 } }); // MongoDB-style ops
|
|
472
|
+
await db.setDocOpOrIgnore(collections.note, id, { $inc: { views: 1 } });
|
|
591
473
|
```
|
|
592
474
|
|
|
475
|
+
Supported update operators: `$inc`, `$addToSet`, `$pull`, `$unset`, `$set`. All keys are dot-notation, fully typed against the collection's schema.
|
|
476
|
+
|
|
593
477
|
### Reading
|
|
594
478
|
|
|
595
479
|
```typescript
|
|
596
|
-
const
|
|
597
|
-
const
|
|
480
|
+
const doc = await db.getDoc(collections.note, id);
|
|
481
|
+
const docs = await db.getDocs(collections.note, { userId }, { sort: { created: -1 }, limit: 20 });
|
|
598
482
|
|
|
599
|
-
//
|
|
483
|
+
// Typed SQL-native query API (preferred for new code)
|
|
484
|
+
const notes = await db.find(collections.note, { userId, done: { $ne: true } }, { sort: { created: -1 }, limit: 20 });
|
|
485
|
+
const count = await db.findCount(collections.note, { userId });
|
|
486
|
+
const sample = await db.findRandom(collections.note, { userId }, 5);
|
|
487
|
+
|
|
488
|
+
// Aggregation pipelines (legacy / advanced)
|
|
600
489
|
const results = await db.getQuery<MyResult>('note', pipeline, { skip, limit });
|
|
601
|
-
const
|
|
602
|
-
const raw = await db.getQueryRaw<T>('note', pipeline);
|
|
490
|
+
const total = await db.getQueryCount('note', pipeline);
|
|
603
491
|
|
|
604
|
-
// Dynamic/untyped access
|
|
605
|
-
|
|
606
|
-
|
|
492
|
+
// Dynamic / untyped access — when the collection name is a runtime string
|
|
493
|
+
await db.rawGetDoc('note', id);
|
|
494
|
+
await db.rawGetDocs('note', filter);
|
|
607
495
|
```
|
|
608
496
|
|
|
609
497
|
### Deleting
|
|
610
498
|
|
|
611
499
|
```typescript
|
|
612
|
-
await db.deleteDoc(collections.note, id);
|
|
613
|
-
await db.
|
|
500
|
+
await db.deleteDoc(collections.note, id); // cascade-deletes children
|
|
501
|
+
await db.deleteWhere(collections.note, { userId }); // typed bulk delete
|
|
502
|
+
await db.deleteQuery(collections.note, { userId }); // legacy untyped bulk delete
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
Pass `deleteHandlers` as the 5th argument to `createApp` to run per-collection `onDelete` callbacks.
|
|
506
|
+
|
|
507
|
+
### Search
|
|
508
|
+
|
|
509
|
+
```typescript
|
|
510
|
+
// Full-text search — requires `search: { fields, language? }` on the collection
|
|
511
|
+
const hits = await db.searchDocs(collections.note, 'react hooks', { limit: 10 });
|
|
512
|
+
|
|
513
|
+
// Vector search — requires `vector: { dimensions, source }` (uses Qdrant)
|
|
514
|
+
const similar = await db.vectorSearch(collections.note, embeddingVector, { limit: 10 });
|
|
614
515
|
```
|
|
615
516
|
|
|
616
517
|
### Caching
|
|
617
518
|
|
|
618
519
|
```typescript
|
|
619
|
-
|
|
520
|
+
db.cacheGet<MyType>(key);
|
|
620
521
|
db.cacheSet(key, value, ttlMs);
|
|
621
|
-
db.cacheDelete(key);
|
|
622
|
-
const
|
|
522
|
+
db.cacheDelete(key); // broadcasts invalidation via NATS
|
|
523
|
+
const k = db.cacheKey('prefix', id);
|
|
623
524
|
```
|
|
624
525
|
|
|
625
526
|
### Helpers
|
|
626
527
|
|
|
627
528
|
```typescript
|
|
628
|
-
import { createUserHelper } from 'ugly-app';
|
|
629
|
-
import { dbDefaults } from 'ugly-app/shared';
|
|
529
|
+
import { createUserHelper, dbDefaults } from 'ugly-app';
|
|
630
530
|
|
|
631
|
-
|
|
632
|
-
|
|
531
|
+
const newDoc = { _id: crypto.randomUUID(), ...dbDefaults(), title: 'Hi' };
|
|
532
|
+
// ^^^^^^^^^^^^^^^ { version: 1, created, updated }
|
|
633
533
|
|
|
634
|
-
// createUserHelper — typed user CRUD with get, set, update methods
|
|
635
534
|
const userHelper = createUserHelper<User>(collections.user);
|
|
636
535
|
const user = await userHelper.get(db, userId);
|
|
637
|
-
await userHelper.set(db, { id: userId, ...dbDefaults(), email });
|
|
638
536
|
```
|
|
639
537
|
|
|
640
|
-
###
|
|
538
|
+
### Direct SQL & infra
|
|
641
539
|
|
|
642
|
-
|
|
540
|
+
Imports available from `ugly-app`:
|
|
643
541
|
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
indexes: [
|
|
650
|
-
{ fields: { userId: 1, created: -1 } },
|
|
651
|
-
{ fields: { title: 1 }, unique: true },
|
|
652
|
-
],
|
|
653
|
-
},
|
|
654
|
-
});
|
|
655
|
-
```
|
|
656
|
-
|
|
657
|
-
After adding or modifying indexes:
|
|
658
|
-
1. Run `npm run db:schema-gen` to generate a migration file
|
|
659
|
-
2. Run `npm run db:migrate` to apply the migration
|
|
542
|
+
- `pgQuery(sql, params?)` — parameterized SQL on the data proxy.
|
|
543
|
+
- `ensureTable(...)`, `tableExists(...)`, `ensureSearchColumn(...)`.
|
|
544
|
+
- `ensureQdrantCollection(...)`, `upsertVector(...)`, `searchVectors(...)`, `deleteVector(...)`, `deleteQdrantCollection(...)`.
|
|
545
|
+
- `connectNats()`, `natsPublish(subject, payload)`, `natsSubscribe(subject, cb)`, `ensureKvBucket(name, opts)`, `jsPublish(...)`, `jsConsumerCreate(...)`, `jsConsumerConsume(...)`.
|
|
546
|
+
- `subscribeCollection`, `subscribeDoc`, `subscribeDocKey` — NATS subjects emitted by the data proxy on writes.
|
|
660
547
|
|
|
661
548
|
---
|
|
662
549
|
|
|
663
550
|
## AI
|
|
664
551
|
|
|
665
|
-
|
|
552
|
+
AI calls are proxied through ugly.bot — your app never holds an AI provider key. Pass `UGLY_BOT_TOKEN` in the environment and the framework handles routing, balance tracking, retries, and per-user billing.
|
|
553
|
+
|
|
554
|
+
### Server-side text generation
|
|
666
555
|
|
|
667
556
|
```typescript
|
|
668
557
|
import { createTextGenClient } from 'ugly-app';
|
|
669
|
-
const textGen = createTextGenClient();
|
|
558
|
+
const textGen = createTextGenClient(userId);
|
|
670
559
|
|
|
671
|
-
const text
|
|
672
|
-
const json = await textGen.generateJson(schema, messages); // Zod schema, retries on parse failure
|
|
673
|
-
const result = await textGen.generateWithTools(messages, tools); // automatic tool-call loop
|
|
560
|
+
const text = await textGen.generate(messages, { model: 'gemini_2_5_flash' });
|
|
674
561
|
```
|
|
675
562
|
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
563
|
+
Or call the framework `textGen` request directly:
|
|
564
|
+
|
|
565
|
+
```typescript
|
|
566
|
+
import { uglyBotRequest } from 'ugly-app';
|
|
567
|
+
const { message } = await uglyBotRequest<{ message: { content: string } }>('textGen', {
|
|
568
|
+
model: 'gemini_2_5_flash',
|
|
569
|
+
messages: [{ role: 'user', content: 'Hello!' }],
|
|
570
|
+
options: { maxTokens: 512 },
|
|
571
|
+
});
|
|
572
|
+
```
|
|
685
573
|
|
|
686
|
-
|
|
574
|
+
Available models are exposed via `textGenModels` / `textGenModelData` from `ugly-app` — the platform supports Claude, GPT, Gemini, Together, Groq, Fireworks, and Kie families.
|
|
687
575
|
|
|
688
|
-
###
|
|
576
|
+
### Server-side image generation
|
|
689
577
|
|
|
690
578
|
```typescript
|
|
691
579
|
import { createImageGenClient } from 'ugly-app';
|
|
692
|
-
const imageGen = createImageGenClient();
|
|
580
|
+
const imageGen = createImageGenClient(userId);
|
|
693
581
|
|
|
694
|
-
const url = await imageGen.generate(
|
|
582
|
+
const url = await imageGen.generate('A red panda eating noodles', { model: 'flux_schnell' });
|
|
695
583
|
```
|
|
696
584
|
|
|
697
|
-
|
|
698
|
-
|----------|-----------------|
|
|
699
|
-
| Together AI (FLUX schnell) | `'together'` |
|
|
700
|
-
| FAL (FLUX pro) | `'fal'` |
|
|
701
|
-
| Google (Imagen 3) | `'google'` |
|
|
702
|
-
| Wavespeed | `'wavespeed'` |
|
|
703
|
-
| Kie.ai (Kolors) | `'kie'` |
|
|
585
|
+
`imageGenModels` / `imageGenModelData` enumerate available models (Together FLUX, FAL, Google Imagen, Wavespeed, Kie Kolors).
|
|
704
586
|
|
|
705
587
|
### Embeddings
|
|
706
588
|
|
|
707
589
|
```typescript
|
|
708
590
|
import { createEmbeddingClient, cosineSimilarity } from 'ugly-app';
|
|
709
591
|
const embeddings = createEmbeddingClient();
|
|
710
|
-
const
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
### Speech-to-text (STT)
|
|
714
|
-
|
|
715
|
-
Server-side STT uses a provider registry pattern. Providers auto-register when their API key env var is set.
|
|
716
|
-
|
|
717
|
-
```typescript
|
|
718
|
-
import { registerSTTProvider, selectSTTProvider, getAllSTTProviders } from 'ugly-app';
|
|
719
|
-
```
|
|
720
|
-
|
|
721
|
-
**Built-in STT providers:**
|
|
722
|
-
|
|
723
|
-
| Provider | Import | Env var | Mode |
|
|
724
|
-
|----------|--------|---------|------|
|
|
725
|
-
| Deepgram (nova-2) | `deepgramSTTProvider` | `DEEPGRAM_API_KEY` | Real-time streaming via WebSocket |
|
|
726
|
-
| OpenAI Whisper | `openAIWhisperSTTProvider` | `OPENAI_API_KEY` | Batch (buffers audio, transcribes on stop) |
|
|
727
|
-
| Groq Whisper | `groqWhisperSTTProvider` | `GROQ_API_KEY` | Batch |
|
|
728
|
-
|
|
729
|
-
**STT provider interface:**
|
|
730
|
-
|
|
731
|
-
```typescript
|
|
732
|
-
interface STTProvider {
|
|
733
|
-
name: string;
|
|
734
|
-
apiKeyEnv: string;
|
|
735
|
-
connect(
|
|
736
|
-
onTranscript: (result: STTTranscript) => void,
|
|
737
|
-
onError: (err: string) => void,
|
|
738
|
-
lang?: string,
|
|
739
|
-
options?: STTConnectOptions,
|
|
740
|
-
onUsage?: (report: STTUsageReport) => void,
|
|
741
|
-
): Promise<STTSession>;
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
interface STTSession {
|
|
745
|
-
sendAudio(pcm16: Buffer): void; // PCM16 at 16kHz mono
|
|
746
|
-
stop(): Promise<void>;
|
|
747
|
-
}
|
|
748
|
-
|
|
749
|
-
interface STTTranscript { text: string; isFinal: boolean; lang?: string; words?: STTWord[] }
|
|
750
|
-
```
|
|
751
|
-
|
|
752
|
-
**Client-side hook:**
|
|
753
|
-
|
|
754
|
-
```typescript
|
|
755
|
-
import { useSTT } from 'ugly-app/client';
|
|
756
|
-
const { start, stop, transcript, isListening } = useSTT(socket, options);
|
|
757
|
-
```
|
|
758
|
-
|
|
759
|
-
### Text-to-speech (TTS)
|
|
760
|
-
|
|
761
|
-
```typescript
|
|
762
|
-
import { registerTTSProvider, selectTTSProvider, azureTTSProvider } from 'ugly-app';
|
|
763
|
-
```
|
|
764
|
-
|
|
765
|
-
**Built-in TTS provider:**
|
|
766
|
-
|
|
767
|
-
| Provider | Import | Env vars |
|
|
768
|
-
|----------|--------|----------|
|
|
769
|
-
| Azure TTS | `azureTTSProvider` | `AZURE_TTS_KEY`, `AZURE_TTS_REGION` |
|
|
770
|
-
|
|
771
|
-
**TTS provider interface:**
|
|
772
|
-
|
|
773
|
-
```typescript
|
|
774
|
-
interface TTSProvider {
|
|
775
|
-
name: string;
|
|
776
|
-
apiKeyEnv: string;
|
|
777
|
-
stream(text: string, voice: string, options?: TTSStreamOptions): AsyncGenerator<TTSChunk>;
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
interface TTSChunk {
|
|
781
|
-
audio: Buffer; // PCM16, mono, 24kHz
|
|
782
|
-
word?: string;
|
|
783
|
-
startMs?: number;
|
|
784
|
-
durationMs?: number;
|
|
785
|
-
visemes?: TTSViseme[]; // When requestVisemes=true (for lip sync)
|
|
786
|
-
}
|
|
787
|
-
```
|
|
788
|
-
|
|
789
|
-
**Client-side hook:**
|
|
790
|
-
|
|
791
|
-
```typescript
|
|
792
|
-
import { useTTS, AudioPlayer, AudioRecorder } from 'ugly-app/client';
|
|
592
|
+
const vector = await embeddings.embed('hello world');
|
|
593
|
+
const sim = cosineSimilarity(vectorA, vectorB);
|
|
793
594
|
```
|
|
794
595
|
|
|
795
596
|
### Web search
|
|
796
597
|
|
|
797
598
|
```typescript
|
|
798
|
-
import { createWebSearchClient
|
|
599
|
+
import { createWebSearchClient } from 'ugly-app';
|
|
799
600
|
const search = createWebSearchClient(userId);
|
|
800
601
|
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
602
|
+
await search.search({ query: 'react 19', limit: 10 });
|
|
603
|
+
await search.summarize({ url: 'https://...' });
|
|
604
|
+
await search.enrichWeb({ query: 'topic' });
|
|
605
|
+
await search.enrichNews({ query: 'topic' });
|
|
805
606
|
```
|
|
806
607
|
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
| Method | Description |
|
|
810
|
-
|--------|-------------|
|
|
811
|
-
| `search({ query, limit? })` | Web search — returns `{ items, related? }` |
|
|
812
|
-
| `summarize({ url?, text? })` | Summarize a URL or text — returns summary string |
|
|
813
|
-
| `enrichWeb({ query })` | Enriched web results |
|
|
814
|
-
| `enrichNews({ query })` | Enriched news results |
|
|
815
|
-
|
|
816
|
-
Built-in providers: Kagi (`KAGI_API_KEY`) and UglyBot.
|
|
608
|
+
### Client-side AI calls
|
|
817
609
|
|
|
818
|
-
|
|
610
|
+
Calls from React components go through the framework RPC pipeline — no token plumbing in the browser:
|
|
819
611
|
|
|
820
612
|
```typescript
|
|
821
|
-
import {
|
|
613
|
+
import { callTextGen, callJsonGen, callImageGen } from 'ugly-app/client';
|
|
822
614
|
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
615
|
+
const text = await callTextGen({ messages, model: 'gemini_2_5_flash' });
|
|
616
|
+
const json = await callJsonGen({ messages, schema, model: 'gemini_2_5_flash' });
|
|
617
|
+
const image = await callImageGen({ prompt: 'a corgi astronaut', model: 'flux_schnell' });
|
|
826
618
|
```
|
|
827
619
|
|
|
828
|
-
###
|
|
620
|
+
### STT / TTS
|
|
829
621
|
|
|
830
|
-
|
|
622
|
+
Speech goes **directly** from the browser to ugly.bot — never proxied through your app server.
|
|
831
623
|
|
|
832
624
|
```typescript
|
|
833
|
-
import {
|
|
625
|
+
import { useSTT, useTTS, AudioPlayer, AudioRecorder } from 'ugly-app/client';
|
|
834
626
|
|
|
835
|
-
const
|
|
836
|
-
const
|
|
837
|
-
const image = await callImageGen(input);
|
|
627
|
+
const { start, stop, transcript, isListening } = useSTT(socket, options);
|
|
628
|
+
const { speak, stop: stopTTS } = useTTS(socket, { voice: 'alloy' });
|
|
838
629
|
```
|
|
839
630
|
|
|
840
|
-
These call `POST /ai/request` (same-origin, avoids CORS). The server verifies the user JWT and forwards to `https://ugly.bot` using the `UGLY_BOT_TOKEN` env var.
|
|
841
|
-
|
|
842
631
|
---
|
|
843
632
|
|
|
844
633
|
## Storage
|
|
845
634
|
|
|
635
|
+
S3-compatible. Two logical buckets:
|
|
636
|
+
|
|
637
|
+
- **`temp`** — short-lived uploads (presigned PUT from the browser).
|
|
638
|
+
- **`public`** — durable, served by CDN.
|
|
639
|
+
|
|
640
|
+
Server-side:
|
|
641
|
+
|
|
846
642
|
```typescript
|
|
847
|
-
|
|
848
|
-
const
|
|
643
|
+
import { createStorageClient } from 'ugly-app';
|
|
644
|
+
const storage = createStorageClient();
|
|
849
645
|
|
|
850
|
-
|
|
646
|
+
await storage.put('temp', key, buffer, 'image/png');
|
|
851
647
|
const publicUrl = await storage.moveToPublic(tempKey, destKey);
|
|
852
|
-
|
|
853
|
-
// Get a public URL
|
|
854
648
|
const url = storage.url('public', destKey);
|
|
855
|
-
|
|
856
|
-
// Browser direct upload via presigned URL
|
|
857
649
|
const { uploadUrl, resultUrl } = await storage.presignedPut('temp', key);
|
|
858
650
|
```
|
|
859
651
|
|
|
860
|
-
|
|
652
|
+
Client-side, use `socket.uploadFile(file, key)` — it requests a presigned URL via the built-in `uploadUrl` framework request and streams the upload. In dev, uploads go through a same-origin `/_s3` proxy to avoid CORS with local MinIO.
|
|
861
653
|
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
```typescript
|
|
865
|
-
interface StorageClient {
|
|
866
|
-
put(bucket: 'public' | 'temp', key: string, body: Buffer, contentType: string): Promise<string>;
|
|
867
|
-
moveToPublic(tempKey: string, destKey: string): Promise<string>;
|
|
868
|
-
url(bucket: 'public' | 'temp', key: string): string;
|
|
869
|
-
presignedPut(bucket: 'temp', key: string): Promise<{ uploadUrl: string; resultUrl: string }>;
|
|
870
|
-
}
|
|
871
|
-
```
|
|
872
|
-
|
|
873
|
-
Static build-time assets go in `client/public/`. Never hardcode `/asset/...` paths — use the `buildId` from `shared/Build.ts`.
|
|
654
|
+
`STORAGE_KEY_PREFIX` (env) prefixes all keys — useful for per-environment isolation.
|
|
874
655
|
|
|
875
656
|
---
|
|
876
657
|
|
|
877
|
-
##
|
|
878
|
-
|
|
879
|
-
Usage-based billing with per-user limits, global provider limits, pre-paid credits, and threshold alerts.
|
|
658
|
+
## Workers & cron
|
|
880
659
|
|
|
881
660
|
```typescript
|
|
882
|
-
|
|
661
|
+
// shared/cron.ts
|
|
662
|
+
import { defineWorkers, z } from 'ugly-app/shared';
|
|
883
663
|
|
|
884
|
-
const
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
664
|
+
export const cronTasks = defineWorkers({
|
|
665
|
+
dailyCleanup: {
|
|
666
|
+
schedule: '0 3 * * *', // every day at 03:00 UTC
|
|
667
|
+
description: 'Delete completed todos older than 30 days',
|
|
668
|
+
},
|
|
669
|
+
resyncSearch: {
|
|
670
|
+
inputSchema: z.object({ since: z.string().datetime() }),
|
|
671
|
+
description: 'Re-embed search vectors since the given ISO timestamp',
|
|
888
672
|
},
|
|
889
|
-
profitMarginPct: 0.2, // 20% markup on costs
|
|
890
|
-
});
|
|
891
|
-
|
|
892
|
-
// Charge a user
|
|
893
|
-
await billing.charge({
|
|
894
|
-
userId: '...',
|
|
895
|
-
provider: 'openai',
|
|
896
|
-
model: 'gpt-4o',
|
|
897
|
-
type: 'textGen', // 'textGen' | 'imageGen' | 'stt' | 'tts' | 'embedding' | 'service'
|
|
898
|
-
costUsd: 0.03,
|
|
899
|
-
inputTokens: 1000,
|
|
900
|
-
outputTokens: 500,
|
|
901
673
|
});
|
|
674
|
+
```
|
|
902
675
|
|
|
903
|
-
|
|
904
|
-
|
|
676
|
+
```typescript
|
|
677
|
+
// server/index.ts
|
|
678
|
+
const cronHandlers: WorkerHandlers<typeof cronTasks> = {
|
|
679
|
+
dailyCleanup: async () => { /* runs on schedule */ },
|
|
680
|
+
resyncSearch: async ({ since }) => { /* runs on manual trigger from studio */ },
|
|
681
|
+
};
|
|
905
682
|
|
|
906
|
-
|
|
907
|
-
|
|
683
|
+
configurator.setWorkers(cronTasks, cronHandlers);
|
|
684
|
+
```
|
|
908
685
|
|
|
909
|
-
|
|
910
|
-
const usage = await billing.getSpend(userId, { from, to });
|
|
686
|
+
Each worker can have `inputSchema`, `outputSchema`, `schedule`, `timeout`, `description`. Workers without a schedule are still invocable via `POST /_workers/run` (auth: localhost in dev, `Authorization: Bearer $CRON_SECRET` in prod). Scheduled workers also appear in `/_cron/manifest` for the deploy orchestrator.
|
|
911
687
|
|
|
912
|
-
|
|
913
|
-
billing.setUserThresholdCallback((userId, period, spend, limit) => { /* alert */ });
|
|
914
|
-
billing.setGlobalThresholdCallback((period, spend, limit) => { /* alert */ });
|
|
915
|
-
```
|
|
688
|
+
---
|
|
916
689
|
|
|
917
|
-
|
|
690
|
+
## Localization
|
|
918
691
|
|
|
919
692
|
```typescript
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
})
|
|
693
|
+
configurator.setStrings({
|
|
694
|
+
defaultLang: 'en',
|
|
695
|
+
langs: ['en', 'es'],
|
|
696
|
+
criticalKeys: ['app.title', 'nav.home'],
|
|
697
|
+
getTable: (lang) => tables[lang] ?? tables.en,
|
|
698
|
+
});
|
|
926
699
|
```
|
|
927
700
|
|
|
928
|
-
The
|
|
701
|
+
The framework injects `window.__LANG__`, `window.__STRINGS_VERSION__`, and `window.__CRITICAL_STRINGS__` into SSR HTML. Use `useLocalizer()` / `useStrings()` / `useLang()` / `useChangeLanguage()` on the client.
|
|
929
702
|
|
|
930
703
|
---
|
|
931
704
|
|
|
932
705
|
## Experiments
|
|
933
706
|
|
|
934
|
-
A/B testing with deterministic user bucketing and event tracking.
|
|
935
|
-
|
|
936
707
|
```typescript
|
|
937
|
-
// shared/experiments.ts
|
|
938
708
|
import type { Experiment } from 'ugly-app/shared';
|
|
939
709
|
|
|
940
710
|
export const experiments: Experiment[] = [
|
|
941
711
|
{
|
|
942
712
|
id: 'new-onboarding',
|
|
943
|
-
name: 'New Onboarding
|
|
944
|
-
description: 'Test the redesigned onboarding',
|
|
713
|
+
name: 'New Onboarding',
|
|
945
714
|
active: true,
|
|
946
715
|
branches: [
|
|
947
|
-
{ id: 'control',
|
|
948
|
-
{ id: 'variant',
|
|
716
|
+
{ id: 'control', weight: 50 },
|
|
717
|
+
{ id: 'variant', weight: 50 },
|
|
949
718
|
],
|
|
950
|
-
events: ['ONBOARDING_COMPLETE'
|
|
719
|
+
events: ['ONBOARDING_COMPLETE'],
|
|
951
720
|
},
|
|
952
721
|
];
|
|
953
|
-
```
|
|
954
|
-
|
|
955
|
-
**Server-side assignment:**
|
|
956
|
-
|
|
957
|
-
```typescript
|
|
958
|
-
import { getExperimentAssignments, getExperimentBranch } from 'ugly-app';
|
|
959
|
-
|
|
960
|
-
// Get all active experiment assignments for a user
|
|
961
|
-
const branches = getExperimentAssignments(userId, sessionId, experiments);
|
|
962
|
-
// => { 'new-onboarding': 'variant' }
|
|
963
|
-
|
|
964
|
-
// Get a single experiment branch
|
|
965
|
-
const branch = getExperimentBranch(experiment, userId, sessionId);
|
|
966
|
-
```
|
|
967
|
-
|
|
968
|
-
Bucketing uses a deterministic hash of `experimentId:userId` (or `sessionId` if no user), so the same user always gets the same branch. Weights control the relative distribution across branches.
|
|
969
|
-
|
|
970
|
-
---
|
|
971
|
-
|
|
972
|
-
## Event logging
|
|
973
|
-
|
|
974
|
-
Server-side event capture for analytics, tied to experiments.
|
|
975
|
-
|
|
976
|
-
```typescript
|
|
977
|
-
import { eventLogCapture, eventLogServerCapture } from 'ugly-app';
|
|
978
|
-
|
|
979
|
-
// Capture with returned eventId
|
|
980
|
-
const { eventId } = await eventLogCapture({
|
|
981
|
-
eventName: 'BUTTON_CLICK',
|
|
982
|
-
sessionId,
|
|
983
|
-
userId,
|
|
984
|
-
properties: { page: 'home' },
|
|
985
|
-
experimentBranches: branches,
|
|
986
|
-
}, userId);
|
|
987
|
-
|
|
988
|
-
// Fire-and-forget server capture
|
|
989
|
-
await eventLogServerCapture('SESSION_START', { source: 'web' }, sessionId, userId, branches);
|
|
990
|
-
```
|
|
991
|
-
|
|
992
|
-
**Query functions:**
|
|
993
|
-
|
|
994
|
-
| Function | Description |
|
|
995
|
-
|----------|-------------|
|
|
996
|
-
| `eventLogGetList(input)` | Paginated event list (cursor, date range, filters) |
|
|
997
|
-
| `eventLogGetTopUsers(input)` | Top users by event count |
|
|
998
|
-
| `eventLogGetTopSessions(input)` | Top sessions by event count |
|
|
999
|
-
| `eventLogGetTopEvents(input)` | Top events by frequency |
|
|
1000
|
-
| `eventLogGetCounts(input)` | Time-series counts (granularity: `'seconds'` \| `'minutes'` \| `'days'`) |
|
|
1001
|
-
| `eventLogGetUniqueUsersCounts(input)` | Unique users per time interval |
|
|
1002
|
-
| `eventLogGetUniqueSessionsCounts(input)` | Unique sessions per time interval |
|
|
1003
|
-
|
|
1004
|
-
---
|
|
1005
|
-
|
|
1006
|
-
## Additional server APIs
|
|
1007
|
-
|
|
1008
|
-
### Email
|
|
1009
|
-
|
|
1010
|
-
```typescript
|
|
1011
|
-
import { sendEmail, sendTemplateEmail, loadEmailTemplate } from 'ugly-app';
|
|
1012
|
-
|
|
1013
|
-
await sendEmail({ to: 'user@example.com', subject: 'Hello', html: '<p>Hi</p>' });
|
|
1014
|
-
await sendTemplateEmail('welcome', { name: 'Alice' }, { to: 'user@example.com' });
|
|
1015
|
-
```
|
|
1016
|
-
|
|
1017
|
-
### Push notifications
|
|
1018
|
-
|
|
1019
|
-
```typescript
|
|
1020
|
-
import { sendPush, sendFcmPush } from 'ugly-app';
|
|
1021
|
-
|
|
1022
|
-
await sendPush(userId, { title: 'New message', body: 'You have a new message' });
|
|
1023
|
-
```
|
|
1024
|
-
|
|
1025
|
-
### NATS (pub/sub)
|
|
1026
|
-
|
|
1027
|
-
```typescript
|
|
1028
|
-
import { natsPublish, natsSubscribe, subscribeCollection, subscribeDoc } from 'ugly-app';
|
|
1029
|
-
|
|
1030
|
-
natsPublish('my.subject', payload);
|
|
1031
|
-
const sub = natsSubscribe('my.subject', (msg) => { /* ... */ });
|
|
1032
|
-
sub(); // unsubscribe
|
|
1033
|
-
```
|
|
1034
722
|
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
```typescript
|
|
1038
|
-
import { getRedisClient, redisGet, redisSet, redisDel, redisPublish, redisSubscribe } from 'ugly-app';
|
|
1039
|
-
const redis = getRedisClient();
|
|
1040
|
-
```
|
|
1041
|
-
|
|
1042
|
-
### Worker queues
|
|
1043
|
-
|
|
1044
|
-
```typescript
|
|
1045
|
-
import { createWorkerQueue } from 'ugly-app';
|
|
1046
|
-
|
|
1047
|
-
const queue = createWorkerQueue({
|
|
1048
|
-
streamName: 'JOBS', // NATS stream name (default: 'JOBS')
|
|
1049
|
-
concurrency: 10, // max concurrent jobs (default: 10)
|
|
1050
|
-
maxRetries: 3, // max retry attempts (default: 3)
|
|
1051
|
-
clockServerOnly: true, // only process if IS_CLOCK_SERVER=true (default: true)
|
|
1052
|
-
});
|
|
1053
|
-
|
|
1054
|
-
queue.registerHandler<MyPayload>('sendEmail', async (job) => {
|
|
1055
|
-
job.working(); // extend ack deadline for long-running jobs
|
|
1056
|
-
await doWork(job.payload);
|
|
1057
|
-
});
|
|
1058
|
-
|
|
1059
|
-
await queue.enqueue('sendEmail', { to: 'user@example.com' }, { delay: 5000 });
|
|
1060
|
-
|
|
1061
|
-
configurator.setWorkerQueue(queue); // register with the app for lifecycle management
|
|
1062
|
-
```
|
|
1063
|
-
|
|
1064
|
-
**Scheduled tasks** — prevent duplicate enqueuing via MongoDB upsert:
|
|
1065
|
-
|
|
1066
|
-
```typescript
|
|
1067
|
-
import { enqueueTask } from 'ugly-app';
|
|
1068
|
-
|
|
1069
|
-
await enqueueTask(taskDoc, queue, { delay: 60000 });
|
|
1070
|
-
```
|
|
1071
|
-
|
|
1072
|
-
### Billing
|
|
1073
|
-
|
|
1074
|
-
```typescript
|
|
1075
|
-
import { initBillingGateway, getBillingGateway } from 'ugly-app';
|
|
1076
|
-
|
|
1077
|
-
await initBillingGateway({ /* config */ });
|
|
1078
|
-
const billing = getBillingGateway();
|
|
1079
|
-
```
|
|
1080
|
-
|
|
1081
|
-
### Client error capture
|
|
1082
|
-
|
|
1083
|
-
```typescript
|
|
1084
|
-
import { captureClientError, initClientLogger } from 'ugly-app/client';
|
|
1085
|
-
|
|
1086
|
-
initClientLogger(); // call once at startup — captures unhandled errors
|
|
1087
|
-
captureClientError(error); // manually report an error to POST /api/client-error
|
|
1088
|
-
```
|
|
1089
|
-
|
|
1090
|
-
### Feedback
|
|
1091
|
-
|
|
1092
|
-
```typescript
|
|
1093
|
-
import { FeedbackButton, setFeedbackContext, clearFeedbackContext } from 'ugly-app/client';
|
|
1094
|
-
|
|
1095
|
-
// Render the built-in feedback button (bottom-right, always at [data-id="feedback-button"])
|
|
1096
|
-
<FeedbackButton />
|
|
1097
|
-
|
|
1098
|
-
// Set contextual data attached to feedback submissions
|
|
1099
|
-
setFeedbackContext({ page: 'editor', noteId: '123' });
|
|
1100
|
-
clearFeedbackContext();
|
|
723
|
+
configurator.setExperiments(experiments);
|
|
1101
724
|
```
|
|
1102
725
|
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
### Rate limiting
|
|
1106
|
-
|
|
1107
|
-
Rate limiting is configured per-endpoint in the request definition:
|
|
1108
|
-
|
|
1109
|
-
```typescript
|
|
1110
|
-
submitFeedback: authReq({
|
|
1111
|
-
input: z.object({ ... }),
|
|
1112
|
-
output: z.object({ ... }),
|
|
1113
|
-
rateLimit: { max: 20, window: 60 }, // 20 requests per 60 seconds
|
|
1114
|
-
})
|
|
1115
|
-
```
|
|
1116
|
-
|
|
1117
|
-
The framework enforces rate limits automatically before calling the handler.
|
|
726
|
+
Bucketing is deterministic: `hash(experimentId + userId)` (or `sessionId` for unauthenticated users). The framework's `initSession` / `captureEvent` requests automatically tag events with the user's branch assignments.
|
|
1118
727
|
|
|
1119
728
|
---
|
|
1120
729
|
|
|
@@ -1122,59 +731,19 @@ The framework enforces rate limits automatically before calling the handler.
|
|
|
1122
731
|
|
|
1123
732
|
| Endpoint | Description |
|
|
1124
733
|
|----------|-------------|
|
|
1125
|
-
| `GET /health` | Health check — returns `{ status
|
|
1126
|
-
| `POST /
|
|
1127
|
-
| `POST /auth/
|
|
1128
|
-
| `
|
|
1129
|
-
| `GET /auth/
|
|
1130
|
-
| `
|
|
1131
|
-
| `
|
|
1132
|
-
| `POST /
|
|
1133
|
-
| `GET /
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
Never change a collection field type without writing a migration:
|
|
1140
|
-
|
|
1141
|
-
```typescript
|
|
1142
|
-
// server/migrations/001-add-bio.ts
|
|
1143
|
-
export const name = '001-add-bio';
|
|
1144
|
-
export async function up(db: Db) {
|
|
1145
|
-
await db.collection('user').updateMany({}, { $set: { bio: '' } });
|
|
1146
|
-
}
|
|
1147
|
-
```
|
|
1148
|
-
|
|
1149
|
-
Run with `npm run db:migrate`. Use `npm run db:migrate -- --status` to preview pending migrations.
|
|
1150
|
-
|
|
1151
|
-
---
|
|
1152
|
-
|
|
1153
|
-
## CLI reference
|
|
1154
|
-
|
|
1155
|
-
| Command | Description |
|
|
1156
|
-
|---------|-------------|
|
|
1157
|
-
| `ugly-app init <name>` | Scaffold a new project |
|
|
1158
|
-
| `ugly-app upgrade` | Upgrade framework config files to the latest version |
|
|
1159
|
-
| `ugly-app configure` | Generate `.uglyapp` config |
|
|
1160
|
-
| `ugly-app dev` | Start all dev services (Docker, server, Vite, tsc, eslint) |
|
|
1161
|
-
| `ugly-app build` | Production build |
|
|
1162
|
-
| `ugly-app login` | Login to ugly.bot |
|
|
1163
|
-
| `ugly-app db:migrate` | Run pending migrations (`--status` to preview) |
|
|
1164
|
-
| `ugly-app deploy:single` | Deploy to a single server |
|
|
1165
|
-
| `ugly-app deploy:multi` | Deploy to multiple servers |
|
|
1166
|
-
| `ugly-app publish:assets` | Push static assets to CDN (`--dry-run` to preview) |
|
|
1167
|
-
| `ugly-app purge:assets` | Clean old builds (`--keep <n>`, `--dry-run`) |
|
|
1168
|
-
| `ugly-app test:e2e` | Run Playwright end-to-end tests (`--headed` for browser) |
|
|
1169
|
-
| `ugly-app logs:local` | Query local dev logs |
|
|
1170
|
-
| `ugly-app logs:server` | Query server logs from MongoDB |
|
|
1171
|
-
| `ugly-app error:dev` / `error:prod` | Query error logs (dev tunnel / production) |
|
|
1172
|
-
| `ugly-app perf:dev` / `perf:prod` | Query performance metrics (dev tunnel / production) |
|
|
1173
|
-
| `ugly-app feedback:dev` / `feedback:prod` | Query user feedback (dev tunnel / production) |
|
|
1174
|
-
| `ugly-app auth:create-account` | Create an account in the database |
|
|
1175
|
-
| `ugly-app auth:create-token` | Generate a JWT for a userId |
|
|
1176
|
-
| `ugly-app textGen [prompt]` | Generate text via AI (`--model`, `--system-prompt`, `--max-tokens`, `--json`) |
|
|
1177
|
-
| `ugly-app imageGen [prompt]` | Generate an image via AI (`--model`, `--output <path>`) |
|
|
734
|
+
| `GET /health` | Health check — returns `{ status, timestamp, lastRequestAt }`. |
|
|
735
|
+
| `POST /api/:name` | Dispatch any registered request handler over HTTP. |
|
|
736
|
+
| `POST /auth/verify` | Exchange OAuth code for session cookie. |
|
|
737
|
+
| `POST /auth/logout` | Clear the auth cookie. |
|
|
738
|
+
| `GET /auth/token` | Refresh and return the current token. |
|
|
739
|
+
| `GET /auth/url` | Get the OAuth popup URL. |
|
|
740
|
+
| `GET /_workers/manifest` | Worker definitions (used by ugly-studio). |
|
|
741
|
+
| `POST /_workers/run` | Synchronously invoke a worker handler. |
|
|
742
|
+
| `GET /_workers/runs` | Recent in-memory worker runs (last 200). |
|
|
743
|
+
| `GET /_cron/manifest` | Cron tasks for the deploy orchestrator. |
|
|
744
|
+
| `POST /api/_cron/:taskName` | Trigger a cron task (auth via `CRON_SECRET`). |
|
|
745
|
+
| `POST /internal/email-callback` | Inbound email gateway (auth via `INTERNAL_EMAIL_SECRET`). |
|
|
746
|
+
| `PUT /_s3/*` | Dev-only S3 upload proxy (avoids CORS with MinIO). |
|
|
1178
747
|
|
|
1179
748
|
---
|
|
1180
749
|
|
|
@@ -1182,11 +751,17 @@ Run with `npm run db:migrate`. Use `npm run db:migrate -- --status` to preview p
|
|
|
1182
751
|
|
|
1183
752
|
| Import path | Description |
|
|
1184
753
|
|-------------|-------------|
|
|
1185
|
-
| `ugly-app` | Server
|
|
1186
|
-
| `ugly-app/shared` |
|
|
1187
|
-
| `ugly-app/client` |
|
|
1188
|
-
| `ugly-app/
|
|
1189
|
-
| `ugly-app/
|
|
754
|
+
| `ugly-app` | Server: `createApp`, `TypedDB`, auth, AI clients, NATS, storage, email, push, workers. |
|
|
755
|
+
| `ugly-app/shared` | Cross-tier: `defineRequests`, `defineCollections`, `definePage`, `defineWorkers`, Zod, experiments, time constants. |
|
|
756
|
+
| `ugly-app/client` | React: `bootstrapApp`, `createRouter`, `lazyPage`, `AppProvider`, components, animations, audio, AI helpers. |
|
|
757
|
+
| `ugly-app/conversation/{shared,server,client}` | AI chat sessions with persisted history. |
|
|
758
|
+
| `ugly-app/collab/{server,client}` | Yjs-based collaborative editing. |
|
|
759
|
+
| `ugly-app/markdown/{shared,client}` | Markdown rendering + editor. |
|
|
760
|
+
| `ugly-app/webrtc`, `ugly-app/webrtc/server` | WebRTC video rooms. |
|
|
761
|
+
| `ugly-app/three/{server,client}` | Three.js scene helpers. |
|
|
762
|
+
| `ugly-app/worker` | Worker queue runtime. |
|
|
763
|
+
| `ugly-app/playwright` | Test utilities. |
|
|
764
|
+
| `ugly-app/vite`, `ugly-app/eslint` | Build-tool plugins. |
|
|
1190
765
|
|
|
1191
766
|
---
|
|
1192
767
|
|
|
@@ -1194,75 +769,67 @@ Run with `npm run db:migrate`. Use `npm run db:migrate -- --status` to preview p
|
|
|
1194
769
|
|
|
1195
770
|
| Variable | Description |
|
|
1196
771
|
|----------|-------------|
|
|
1197
|
-
| `
|
|
1198
|
-
| `
|
|
1199
|
-
| `
|
|
1200
|
-
| `
|
|
1201
|
-
| `
|
|
1202
|
-
| `
|
|
1203
|
-
| `
|
|
1204
|
-
| `
|
|
1205
|
-
| `
|
|
1206
|
-
| `
|
|
1207
|
-
| `
|
|
1208
|
-
| `
|
|
1209
|
-
| `
|
|
1210
|
-
| `
|
|
1211
|
-
| `
|
|
1212
|
-
| `
|
|
1213
|
-
| `
|
|
1214
|
-
| `
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
| `GROQ_API_KEY` | Groq key |
|
|
1218
|
-
| `KIE_API_KEY` | Kie.ai key |
|
|
1219
|
-
| `KIE_BASE_URL` | Kie.ai base URL override (optional) |
|
|
1220
|
-
| `DEEPGRAM_API_KEY` | Deepgram STT key |
|
|
1221
|
-
| `AZURE_TTS_KEY` | Azure TTS key |
|
|
1222
|
-
| `AZURE_TTS_REGION` | Azure TTS region |
|
|
1223
|
-
| `KAGI_API_KEY` | Kagi web search key |
|
|
1224
|
-
| `MAILGUN_API_KEY` | Mailgun key |
|
|
1225
|
-
| `MAILGUN_DOMAIN` | Mailgun sending domain |
|
|
1226
|
-
| `MAILGUN_FROM` | Default from address |
|
|
1227
|
-
|
|
1228
|
-
Client-side variables must be prefixed with `VITE_`.
|
|
772
|
+
| `PORT` | Server port (templates default to 4321). |
|
|
773
|
+
| `NODE_ENV` | `development` or `production`. |
|
|
774
|
+
| `UGLY_BOT_TOKEN` | App token for the ugly.bot platform — required for AI, logs, billing. |
|
|
775
|
+
| `UGLY_BOT_URL` | Override the platform base URL (default `https://ugly.bot`). |
|
|
776
|
+
| `DATA_PROXY_URL` | WebSocket URL for the data proxy (default `ws://localhost:4200`). |
|
|
777
|
+
| `DATA_PROXY_TOKEN` | Auth token for the data proxy. |
|
|
778
|
+
| `STORAGE_KEY_PREFIX` | Prefix all storage keys (per-env isolation). |
|
|
779
|
+
| `MINIO_ENDPOINT` | Dev-only S3 endpoint for the upload proxy. |
|
|
780
|
+
| `NATS_PREFIX` / `COMPOSE_PROJECT_NAME` | NATS subject prefix for per-env isolation. |
|
|
781
|
+
| `CLOCK_ENABLED` | `true` to enable `setOnMinuteTick` / `setOnHourlyTick`. |
|
|
782
|
+
| `CRON_SECRET` | Bearer secret for `POST /api/_cron/:taskName` and prod `POST /_workers/run`. |
|
|
783
|
+
| `MAINTAIN_BOT_USER_ID` | User id allowed to access admin-only handlers. |
|
|
784
|
+
| `INTERNAL_EMAIL_SECRET` | Shared secret for `/internal/email-callback`. |
|
|
785
|
+
| `JWT_SECRET` | Required when using `getRequestUser()` for the per-project session cookie. |
|
|
786
|
+
| `APP_DOMAIN` | App domain; combined with `NATS_PREFIX` for `getRequestUser()` validation. |
|
|
787
|
+
| `LOG_CAPTURE_URL` | Studio override for client log capture (empty → ugly.bot default). |
|
|
788
|
+
| `UGLY_APP_HMR` | Set to `false` to disable Vite HMR in dev. |
|
|
789
|
+
| `SCHEMA_CHECK_SKIP` | `true` to start despite schema drift (unsafe). |
|
|
790
|
+
|
|
791
|
+
Browser-visible variables must be prefixed `VITE_` and consumed via `import.meta.env.VITE_*`.
|
|
1229
792
|
|
|
1230
793
|
---
|
|
1231
794
|
|
|
1232
|
-
##
|
|
795
|
+
## CLI
|
|
1233
796
|
|
|
1234
|
-
|
|
797
|
+
| Command | Description |
|
|
798
|
+
|---------|-------------|
|
|
799
|
+
| `ugly-app init <name>` | Scaffold a new project. |
|
|
800
|
+
| `ugly-app upgrade` | Upgrade framework config files to the latest version. |
|
|
801
|
+
| `ugly-app configure` | Generate/update `.uglyapp` config. |
|
|
802
|
+
| `ugly-app login` | Authenticate with ugly.bot. |
|
|
803
|
+
| `ugly-app url` | Print the local dev server URL. |
|
|
804
|
+
| `ugly-app deploy` | Build + push to production infrastructure. |
|
|
805
|
+
| `ugly-app prod --buildId <id>` | Promote a build to prod. |
|
|
806
|
+
| `ugly-app versions` | List deployed versions. |
|
|
807
|
+
| `ugly-app versions:prune` | Clean up non-prod versions. |
|
|
808
|
+
| `ugly-app infra:destroy` | Tear down all project infra. |
|
|
809
|
+
| `ugly-app textGen [prompt]` | Generate text via AI (`--model`, `--system-prompt`, `--max-tokens`, `--json`). |
|
|
810
|
+
| `ugly-app imageGen [prompt]` | Generate an image (`--model`, `--output <path>`). |
|
|
811
|
+
| `ugly-app error:dev` / `error:prod` | Query error logs (your tunnel / production). |
|
|
812
|
+
| `ugly-app perf:dev` / `perf:prod` | Query performance metrics. |
|
|
813
|
+
| `ugly-app feedback:dev` / `feedback:prod` | Query user feedback. |
|
|
814
|
+
| `ugly-app feedback:submit` / `feedback:resolve` | Manage feedback (run with `--help` for flags). |
|
|
815
|
+
|
|
816
|
+
Inside a scaffolded project, the same commands are available via `npm run …` scripts — see `templates/CLAUDE.md` for the full list.
|
|
1235
817
|
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
} from 'ugly-app/shared';
|
|
1249
|
-
|
|
1250
|
-
isDefined(value); // type guard — true if not null/undefined
|
|
1251
|
-
compact([1, null, 2, undefined]); // [1, 2] — filters out null/undefined
|
|
1252
|
-
const debouncedFn = debounce(fn, 300);
|
|
1253
|
-
formatDate(new Date()); // locale-formatted date string
|
|
1254
|
-
formatRelativeTime(new Date()); // "2 hours ago", "just now", etc.
|
|
1255
|
-
|
|
1256
|
-
// Time constants (milliseconds)
|
|
1257
|
-
oneSecond; // 1000
|
|
1258
|
-
oneMinute; // 60_000
|
|
1259
|
-
oneHour; // 3_600_000
|
|
1260
|
-
oneDay; // 86_400_000
|
|
1261
|
-
oneWeek; // 604_800_000
|
|
1262
|
-
```
|
|
818
|
+
---
|
|
819
|
+
|
|
820
|
+
## Migrations
|
|
821
|
+
|
|
822
|
+
Schema changes must be deliberate:
|
|
823
|
+
|
|
824
|
+
1. Update the Zod schema in `shared/collections.ts`.
|
|
825
|
+
2. Run `npm run db:schema-gen` — produces a migration file with compile-blocking `REPLACE_ME` placeholders for any non-trivial change.
|
|
826
|
+
3. Replace every `REPLACE_ME` with the correct migration logic.
|
|
827
|
+
4. Run `npm run db:migrate`.
|
|
828
|
+
|
|
829
|
+
The framework refuses to start when drift is detected (set `SCHEMA_CHECK_SKIP=true` only as a temporary escape hatch).
|
|
1263
830
|
|
|
1264
831
|
---
|
|
1265
832
|
|
|
1266
833
|
## Tech stack
|
|
1267
834
|
|
|
1268
|
-
Node.js · TypeScript · Express · React 19 · Vite ·
|
|
835
|
+
Node.js · TypeScript · Express · React 19 · Vite · PostgreSQL (JSONB) · Qdrant · NATS · S3-compatible storage · Zod · JWT (jose) · ugly.bot platform
|