@omnizap-system/omnizap 2.5.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (425) hide show
  1. package/.clusterfuzzlite/Dockerfile +10 -0
  2. package/.env.example +907 -0
  3. package/.github/codeql/codeql-config.yml +10 -0
  4. package/.github/dependabot.yml +35 -0
  5. package/.github/workflows/ci.yml +73 -0
  6. package/.github/workflows/codeql.yml +106 -0
  7. package/.github/workflows/db-migration-check.yml +98 -0
  8. package/.github/workflows/dependency-review.yml +22 -0
  9. package/.github/workflows/deploy.yml +95 -0
  10. package/.github/workflows/release.yml +106 -0
  11. package/.github/workflows/security-attest-provenance.yml +51 -0
  12. package/.github/workflows/security-gitleaks.yml +34 -0
  13. package/.github/workflows/security-runner-hardening.yml +31 -0
  14. package/.github/workflows/security-scorecard.yml +44 -0
  15. package/.github/workflows/security-zap-baseline.yml +44 -0
  16. package/.github/workflows/security-zap-full-scan.yml +43 -0
  17. package/.github/workflows/security-zizmor.yml +36 -0
  18. package/.github/workflows/wiki-sync.yml +44 -0
  19. package/.gitleaks.toml +15 -0
  20. package/.prettierrc +34 -0
  21. package/CODE_OF_CONDUCT.md +114 -0
  22. package/LICENSE +56 -0
  23. package/README.md +110 -0
  24. package/SECURITY.md +110 -0
  25. package/app/config/index.js +4 -0
  26. package/app/configParts/adminIdentity.js +92 -0
  27. package/app/configParts/baileysConfig.js +1818 -0
  28. package/app/configParts/groupUtils.js +692 -0
  29. package/app/configParts/loggerConfig.js +394 -0
  30. package/app/configParts/messagePersistenceService.js +305 -0
  31. package/app/connection/baileysCompatibility.test.js +40 -0
  32. package/app/connection/baileysDbAuthState.js +344 -0
  33. package/app/connection/socketController.js +2243 -0
  34. package/app/controllers/messageController.js +7 -0
  35. package/app/controllers/messagePipeline/commandMiddleware.js +146 -0
  36. package/app/controllers/messagePipeline/conversationMiddleware.js +183 -0
  37. package/app/controllers/messagePipeline/messagePipelineMiddlewares.test.js +522 -0
  38. package/app/controllers/messagePipeline/postProcessingMiddleware.js +41 -0
  39. package/app/controllers/messagePipeline/preProcessingMiddlewares.js +166 -0
  40. package/app/controllers/messageProcessingPipeline.js +699 -0
  41. package/app/modules/adminModule/AGENT.md +4056 -0
  42. package/app/modules/adminModule/adminAiHelpService.js +56 -0
  43. package/app/modules/adminModule/adminConfigRuntime.js +177 -0
  44. package/app/modules/adminModule/commandConfig.json +7122 -0
  45. package/app/modules/adminModule/groupCommandHandlers.js +1823 -0
  46. package/app/modules/adminModule/groupCommandHandlers.test.js +350 -0
  47. package/app/modules/adminModule/groupEventHandlers.js +399 -0
  48. package/app/modules/aiModule/AGENT.md +547 -0
  49. package/app/modules/aiModule/aiAiHelpService.js +14 -0
  50. package/app/modules/aiModule/aiConfigRuntime.js +135 -0
  51. package/app/modules/aiModule/catCommand.js +967 -0
  52. package/app/modules/aiModule/commandConfig.json +981 -0
  53. package/app/modules/analyticsModule/messageAnalysisEventRepository.js +83 -0
  54. package/app/modules/gameModule/AGENT.md +196 -0
  55. package/app/modules/gameModule/commandConfig.json +366 -0
  56. package/app/modules/gameModule/diceCommand.js +42 -0
  57. package/app/modules/gameModule/gameAiHelpService.js +14 -0
  58. package/app/modules/gameModule/gameConfigRuntime.js +68 -0
  59. package/app/modules/menuModule/AGENT.md +205 -0
  60. package/app/modules/menuModule/commandConfig.json +366 -0
  61. package/app/modules/menuModule/common.js +316 -0
  62. package/app/modules/menuModule/menuAiHelpService.js +14 -0
  63. package/app/modules/menuModule/menuConfigRuntime.js +68 -0
  64. package/app/modules/menuModule/menus.js +66 -0
  65. package/app/modules/playModule/AGENT.md +321 -0
  66. package/app/modules/playModule/commandConfig.json +584 -0
  67. package/app/modules/playModule/playAiHelpService.js +14 -0
  68. package/app/modules/playModule/playCommand.js +1417 -0
  69. package/app/modules/playModule/playConfigRuntime.js +68 -0
  70. package/app/modules/quoteModule/AGENT.md +199 -0
  71. package/app/modules/quoteModule/commandConfig.json +366 -0
  72. package/app/modules/quoteModule/quoteAiHelpService.js +14 -0
  73. package/app/modules/quoteModule/quoteCommand.js +842 -0
  74. package/app/modules/quoteModule/quoteConfigRuntime.js +68 -0
  75. package/app/modules/rpgPokemonModule/AGENT.md +229 -0
  76. package/app/modules/rpgPokemonModule/commandConfig.json +386 -0
  77. package/app/modules/rpgPokemonModule/rpgBattleCanvasRenderer.js +795 -0
  78. package/app/modules/rpgPokemonModule/rpgBattleService.js +2110 -0
  79. package/app/modules/rpgPokemonModule/rpgBattleService.test.js +770 -0
  80. package/app/modules/rpgPokemonModule/rpgEvolutionUtils.js +22 -0
  81. package/app/modules/rpgPokemonModule/rpgPokemonAiHelpService.js +14 -0
  82. package/app/modules/rpgPokemonModule/rpgPokemonCommand.js +174 -0
  83. package/app/modules/rpgPokemonModule/rpgPokemonConfigRuntime.js +68 -0
  84. package/app/modules/rpgPokemonModule/rpgPokemonDomain.js +192 -0
  85. package/app/modules/rpgPokemonModule/rpgPokemonDomain.test.js +93 -0
  86. package/app/modules/rpgPokemonModule/rpgPokemonEvolution.test.js +46 -0
  87. package/app/modules/rpgPokemonModule/rpgPokemonMessages.js +746 -0
  88. package/app/modules/rpgPokemonModule/rpgPokemonRepository.js +1847 -0
  89. package/app/modules/rpgPokemonModule/rpgPokemonService.js +6839 -0
  90. package/app/modules/rpgPokemonModule/rpgProfileCanvasRenderer.js +354 -0
  91. package/app/modules/statsModule/AGENT.md +320 -0
  92. package/app/modules/statsModule/commandConfig.json +540 -0
  93. package/app/modules/statsModule/globalRankingCommand.js +64 -0
  94. package/app/modules/statsModule/rankingCommand.js +41 -0
  95. package/app/modules/statsModule/rankingCommon.js +1305 -0
  96. package/app/modules/statsModule/statsAiHelpService.js +14 -0
  97. package/app/modules/statsModule/statsConfigRuntime.js +68 -0
  98. package/app/modules/stickerModule/AGENT.md +692 -0
  99. package/app/modules/stickerModule/addStickerMetadata.js +239 -0
  100. package/app/modules/stickerModule/commandConfig.json +1216 -0
  101. package/app/modules/stickerModule/convertToWebp.js +367 -0
  102. package/app/modules/stickerModule/stickerAiHelpService.js +14 -0
  103. package/app/modules/stickerModule/stickerCommand.js +446 -0
  104. package/app/modules/stickerModule/stickerConfigRuntime.js +68 -0
  105. package/app/modules/stickerModule/stickerConvertCommand.js +159 -0
  106. package/app/modules/stickerModule/stickerTextCommand.js +653 -0
  107. package/app/modules/stickerPackModule/AGENT.md +215 -0
  108. package/app/modules/stickerPackModule/autoPackCollectorRuntime.js +20 -0
  109. package/app/modules/stickerPackModule/autoPackCollectorService.js +357 -0
  110. package/app/modules/stickerPackModule/commandConfig.json +387 -0
  111. package/app/modules/stickerPackModule/domainEventOutboxRepository.js +227 -0
  112. package/app/modules/stickerPackModule/domainEvents.js +52 -0
  113. package/app/modules/stickerPackModule/semanticReclassificationEngine.js +429 -0
  114. package/app/modules/stickerPackModule/semanticReclassificationEngine.test.js +75 -0
  115. package/app/modules/stickerPackModule/semanticThemeClusterService.js +544 -0
  116. package/app/modules/stickerPackModule/stickerAssetClassificationRepository.js +400 -0
  117. package/app/modules/stickerPackModule/stickerAssetRepository.js +400 -0
  118. package/app/modules/stickerPackModule/stickerAssetReprocessQueueRepository.js +175 -0
  119. package/app/modules/stickerPackModule/stickerAutoPackByTagsRuntime.js +3702 -0
  120. package/app/modules/stickerPackModule/stickerClassificationBackgroundRuntime.js +559 -0
  121. package/app/modules/stickerPackModule/stickerClassificationService.js +557 -0
  122. package/app/modules/stickerPackModule/stickerDedicatedTaskWorkerRuntime.js +249 -0
  123. package/app/modules/stickerPackModule/stickerDomainEventBus.js +65 -0
  124. package/app/modules/stickerPackModule/stickerDomainEventConsumerRuntime.js +208 -0
  125. package/app/modules/stickerPackModule/stickerMarketplaceDriftService.js +99 -0
  126. package/app/modules/stickerPackModule/stickerObjectStorageService.js +285 -0
  127. package/app/modules/stickerPackModule/stickerPackAiHelpService.js +14 -0
  128. package/app/modules/stickerPackModule/stickerPackCommandHandlers.js +1148 -0
  129. package/app/modules/stickerPackModule/stickerPackConfigRuntime.js +68 -0
  130. package/app/modules/stickerPackModule/stickerPackEngagementRepository.js +152 -0
  131. package/app/modules/stickerPackModule/stickerPackErrors.js +30 -0
  132. package/app/modules/stickerPackModule/stickerPackInteractionEventRepository.js +101 -0
  133. package/app/modules/stickerPackModule/stickerPackItemRepository.js +432 -0
  134. package/app/modules/stickerPackModule/stickerPackMarketplaceService.js +313 -0
  135. package/app/modules/stickerPackModule/stickerPackMessageService.js +268 -0
  136. package/app/modules/stickerPackModule/stickerPackRepository.js +450 -0
  137. package/app/modules/stickerPackModule/stickerPackScoreSnapshotRepository.js +179 -0
  138. package/app/modules/stickerPackModule/stickerPackScoreSnapshotRuntime.js +271 -0
  139. package/app/modules/stickerPackModule/stickerPackService.js +733 -0
  140. package/app/modules/stickerPackModule/stickerPackServiceRuntime.js +32 -0
  141. package/app/modules/stickerPackModule/stickerPackUtils.js +107 -0
  142. package/app/modules/stickerPackModule/stickerStorageService.js +559 -0
  143. package/app/modules/stickerPackModule/stickerWorkerPipelineRuntime.js +242 -0
  144. package/app/modules/stickerPackModule/stickerWorkerTaskQueueRepository.js +242 -0
  145. package/app/modules/systemMetricsModule/AGENT.md +193 -0
  146. package/app/modules/systemMetricsModule/commandConfig.json +344 -0
  147. package/app/modules/systemMetricsModule/pingCommand.js +399 -0
  148. package/app/modules/systemMetricsModule/systemMetricsAiHelpService.js +14 -0
  149. package/app/modules/systemMetricsModule/systemMetricsConfigRuntime.js +68 -0
  150. package/app/modules/tiktokModule/AGENT.md +196 -0
  151. package/app/modules/tiktokModule/commandConfig.json +366 -0
  152. package/app/modules/tiktokModule/tiktokAiHelpService.js +14 -0
  153. package/app/modules/tiktokModule/tiktokCommand.js +716 -0
  154. package/app/modules/tiktokModule/tiktokConfigRuntime.js +68 -0
  155. package/app/modules/userModule/AGENT.md +200 -0
  156. package/app/modules/userModule/commandConfig.json +386 -0
  157. package/app/modules/userModule/userAiHelpService.js +14 -0
  158. package/app/modules/userModule/userCommand.js +1155 -0
  159. package/app/modules/userModule/userConfigRuntime.js +68 -0
  160. package/app/modules/waifuPicsModule/AGENT.md +431 -0
  161. package/app/modules/waifuPicsModule/commandConfig.json +780 -0
  162. package/app/modules/waifuPicsModule/waifuPicsAiHelpService.js +14 -0
  163. package/app/modules/waifuPicsModule/waifuPicsCommand.js +586 -0
  164. package/app/modules/waifuPicsModule/waifuPicsConfigRuntime.js +68 -0
  165. package/app/observability/metrics.js +766 -0
  166. package/app/services/ai/aiHelpResponseCacheRepository.js +280 -0
  167. package/app/services/ai/aiLearningRepository.js +400 -0
  168. package/app/services/ai/commandConfigEnrichmentRepository.js +769 -0
  169. package/app/services/ai/commandConfigEnrichmentService.js +452 -0
  170. package/app/services/ai/commandConfigValidationService.js +443 -0
  171. package/app/services/ai/commandToolBuilderService.js +192 -0
  172. package/app/services/ai/conversationRouterService.js +516 -0
  173. package/app/services/ai/geminiService.js +115 -0
  174. package/app/services/ai/geminiService.test.js +87 -0
  175. package/app/services/ai/globalModuleAiHelpService.js +1412 -0
  176. package/app/services/ai/globalToolCallingService.js +203 -0
  177. package/app/services/ai/messageCommandExecutionService.js +391 -0
  178. package/app/services/ai/moduleAiHelpCoreService.js +1099 -0
  179. package/app/services/ai/moduleAiHelpWrapperFactory.js +65 -0
  180. package/app/services/ai/moduleCommandConfigRuntimeService.js +113 -0
  181. package/app/services/ai/moduleToolExecutorService.js +464 -0
  182. package/app/services/ai/moduleToolRegistryService.js +178 -0
  183. package/app/services/ai/toolCandidateSelectorService.js +781 -0
  184. package/app/services/auth/googleWebLinkService.js +80 -0
  185. package/app/services/auth/whatsappLoginLinkService.js +230 -0
  186. package/app/services/external/pokeApiService.js +398 -0
  187. package/app/services/group/groupMetadataService.js +311 -0
  188. package/app/services/infra/dbWriteQueue.js +874 -0
  189. package/app/services/infra/featureFlagService.js +131 -0
  190. package/app/services/infra/queueUtils.js +55 -0
  191. package/app/services/messaging/captchaService.js +491 -0
  192. package/app/services/messaging/messagePersistenceService.js +1 -0
  193. package/app/services/messaging/newsBroadcastService.js +347 -0
  194. package/app/services/sticker/stickerFocusService.js +347 -0
  195. package/app/services/sticker/stickerFocusService.test.js +43 -0
  196. package/app/store/aiPromptStore.js +38 -0
  197. package/app/store/conversationSessionStore.js +131 -0
  198. package/app/store/groupConfigStore.js +58 -0
  199. package/app/store/premiumUserStore.js +54 -0
  200. package/app/utils/antiLink/antiLinkModule.js +700 -0
  201. package/app/utils/http/getImageBufferModule.js +18 -0
  202. package/app/utils/json/jsonSanitizer.js +113 -0
  203. package/app/utils/json/jsonSanitizer.test.js +40 -0
  204. package/app/utils/systemMetrics/systemMetricsModule.js +88 -0
  205. package/app/workers/aiLearningWorker.js +605 -0
  206. package/app/workers/commandConfigEnrichmentWorker.js +242 -0
  207. package/database/index.js +2075 -0
  208. package/database/init.js +151 -0
  209. package/database/migrations/.gitkeep +0 -0
  210. package/database/migrations/20260307_d0_hardening_down.sql +64 -0
  211. package/database/migrations/20260307_d0_hardening_up.sql +79 -0
  212. package/database/migrations/20260307_d1_terms_acceptance_down.sql +11 -0
  213. package/database/migrations/20260307_d1_terms_acceptance_up.sql +37 -0
  214. package/database/migrations/20260307_d2_auth_hardening_down.sql +75 -0
  215. package/database/migrations/20260307_d2_auth_hardening_up.sql +100 -0
  216. package/database/migrations/20260314_d7_canonical_sender_down.sql +53 -0
  217. package/database/migrations/20260314_d7_canonical_sender_up.sql +114 -0
  218. package/database/migrations/20260406_d30_security_analytics_down.sql +95 -0
  219. package/database/migrations/20260406_d30_security_analytics_up.sql +292 -0
  220. package/database/migrations/20260407_d31_web_google_session_token_hardening_down.sql +2 -0
  221. package/database/migrations/20260407_d31_web_google_session_token_hardening_up.sql +17 -0
  222. package/database/migrations/20260408_d32_ai_help_response_cache_down.sql +1 -0
  223. package/database/migrations/20260408_d32_ai_help_response_cache_up.sql +22 -0
  224. package/database/migrations/20260409_d33_ai_learning_tables_down.sql +4 -0
  225. package/database/migrations/20260409_d33_ai_learning_tables_up.sql +52 -0
  226. package/database/migrations/20260410_d34_command_config_enrichment_down.sql +3 -0
  227. package/database/migrations/20260410_d34_command_config_enrichment_up.sql +48 -0
  228. package/database/schema.sql +1186 -0
  229. package/docker-compose.yml +104 -0
  230. package/docs/audits/stickerCatalogController-out-of-scope.md +103 -0
  231. package/docs/audits/stickerCatalogController-symbols.md +58 -0
  232. package/docs/compliance/acceptable-use-policy-2026-03-07.md +35 -0
  233. package/docs/compliance/dpa-b2b-standard-2026-03-07.md +80 -0
  234. package/docs/compliance/monthly-compliance-checklist-2026-03-07.md +88 -0
  235. package/docs/compliance/notice-and-takedown-policy-2026-03-07.md +34 -0
  236. package/docs/compliance/privacy-policy-2026-03-07.md +75 -0
  237. package/docs/compliance/subprocessors-inventory-2026-03-07.md +16 -0
  238. package/docs/database/production-db-evolution-runbook-2026q1.md +365 -0
  239. package/docs/security/dsar-lgpd-runbook-2026-03-07.md +86 -0
  240. package/docs/security/incident-response-lgpd-anpd-runbook-2026-03-07.md +77 -0
  241. package/docs/security/network-hardening-runbook-2026-03-07.md +137 -0
  242. package/docs/seo/omnizap-seo-playbook-br-2026-02-28.md +238 -0
  243. package/docs/seo/satellite-page-template.md +116 -0
  244. package/docs/seo/satellite-pages-phase1.json +364 -0
  245. package/docs/wiki/Home.md +120 -0
  246. package/docs/wiki/pair-extraordinaire-2026-03-08.md +3 -0
  247. package/docs/wiki/recent-changes-2026-03-08.md +47 -0
  248. package/ecosystem.prod.config.cjs +135 -0
  249. package/eslint.config.js +89 -0
  250. package/index.js +488 -0
  251. package/ml/clip_classifier/Dockerfile +18 -0
  252. package/ml/clip_classifier/README.md +118 -0
  253. package/ml/clip_classifier/adaptive_scoring.py +40 -0
  254. package/ml/clip_classifier/classifier.py +654 -0
  255. package/ml/clip_classifier/embedding_store.py +481 -0
  256. package/ml/clip_classifier/env_loader.py +15 -0
  257. package/ml/clip_classifier/llm_label_expander.py +144 -0
  258. package/ml/clip_classifier/main.py +213 -0
  259. package/ml/clip_classifier/requirements.txt +10 -0
  260. package/ml/clip_classifier/similarity_engine.py +74 -0
  261. package/new-logo.png +0 -0
  262. package/observability/alert-rules.yml +60 -0
  263. package/observability/grafana/dashboards/omnizap-mysql.json +136 -0
  264. package/observability/grafana/dashboards/omnizap-overview.json +170 -0
  265. package/observability/grafana/provisioning/dashboards/dashboards.yml +11 -0
  266. package/observability/grafana/provisioning/datasources/datasources.yml +15 -0
  267. package/observability/loki-config.yml +38 -0
  268. package/observability/mysql-setup.sql +46 -0
  269. package/observability/prometheus.yml +35 -0
  270. package/observability/promtail-config.yml +84 -0
  271. package/observability/sticker-catalog-slo.md +83 -0
  272. package/observability/sticker-scale-hardening-rollout.md +128 -0
  273. package/package.json +144 -0
  274. package/public/apple-touch-icon.png +0 -0
  275. package/public/assets/css/commands-react.input.css +71 -0
  276. package/public/assets/css/create-pack-react.input.css +31 -0
  277. package/public/assets/css/home-react.input.css +106 -0
  278. package/public/assets/css/login-react.input.css +58 -0
  279. package/public/assets/css/stickers-react.input.css +18 -0
  280. package/public/assets/css/terms-react.input.css +115 -0
  281. package/public/assets/css/user-react.input.css +57 -0
  282. package/public/assets/images/brand-icon-192.png +0 -0
  283. package/public/assets/images/brand-logo-128.webp +0 -0
  284. package/public/assets/images/hero-banner-1280.jpg +0 -0
  285. package/public/comandos/commands-catalog.json +4517 -0
  286. package/public/css/api-docs.css +161 -0
  287. package/public/css/stickers-admin.css +1288 -0
  288. package/public/css/styles.css +679 -0
  289. package/public/css/systemadm/admin.css +474 -0
  290. package/public/css/systemadm/base.css +73 -0
  291. package/public/css/systemadm/components.css +662 -0
  292. package/public/css/systemadm/layout.css +229 -0
  293. package/public/css/systemadm/tokens.css +56 -0
  294. package/public/favicon-16x16.png +0 -0
  295. package/public/favicon-32x32.png +0 -0
  296. package/public/favicon.ico +0 -0
  297. package/public/js/apps/apiDocsApp.js +235 -0
  298. package/public/js/apps/commandsReactApp.js +528 -0
  299. package/public/js/apps/createPackApp.js +1646 -0
  300. package/public/js/apps/homeReactApp.js +942 -0
  301. package/public/js/apps/loginReactApp.js +496 -0
  302. package/public/js/apps/stickersAdminApp.js +1753 -0
  303. package/public/js/apps/stickersApp.js +3797 -0
  304. package/public/js/apps/termsReactApp.js +528 -0
  305. package/public/js/apps/userApp.js +2540 -0
  306. package/public/js/apps/userProfile/actions.js +66 -0
  307. package/public/js/apps/userReactApp.js +547 -0
  308. package/public/js/catalog.js +950 -0
  309. package/public/pages/api-docs.html +40 -0
  310. package/public/pages/aup.html +158 -0
  311. package/public/pages/comandos.html +41 -0
  312. package/public/pages/dpa.html +227 -0
  313. package/public/pages/home.html +45 -0
  314. package/public/pages/licenca.html +182 -0
  315. package/public/pages/login.html +40 -0
  316. package/public/pages/notice-and-takedown.html +234 -0
  317. package/public/pages/politica-de-privacidade.html +251 -0
  318. package/public/pages/seo-bot-whatsapp-para-grupo.html +350 -0
  319. package/public/pages/seo-bot-whatsapp-sem-programar.html +350 -0
  320. package/public/pages/seo-como-automatizar-avisos-no-whatsapp.html +350 -0
  321. package/public/pages/seo-como-criar-comandos-whatsapp.html +350 -0
  322. package/public/pages/seo-como-evitar-spam-no-whatsapp.html +350 -0
  323. package/public/pages/seo-como-moderar-grupo-whatsapp.html +350 -0
  324. package/public/pages/seo-como-organizar-comunidade-whatsapp.html +350 -0
  325. package/public/pages/seo-melhor-bot-whatsapp-para-grupos.html +350 -0
  326. package/public/pages/stickers-admin.html +31 -0
  327. package/public/pages/stickers-create.html +41 -0
  328. package/public/pages/stickers.html +45 -0
  329. package/public/pages/suboperadores.html +237 -0
  330. package/public/pages/termos-de-uso-texto-integral.html +241 -0
  331. package/public/pages/termos-de-uso.html +41 -0
  332. package/public/pages/user-password-reset.html +32 -0
  333. package/public/pages/user-systemadm.html +508 -0
  334. package/public/pages/user.html +39 -0
  335. package/public/robots.txt +9 -0
  336. package/public/site.webmanifest +24 -0
  337. package/public/sitemap.xml +98 -0
  338. package/schemas/command-config.schema.json +582 -0
  339. package/scripts/baileys-compat-smoke.mjs +12 -0
  340. package/scripts/cache-bust.mjs +142 -0
  341. package/scripts/deploy.sh +916 -0
  342. package/scripts/email-broadcast-terms-update.mjs +170 -0
  343. package/scripts/enrich-command-discovery-fields.mjs +286 -0
  344. package/scripts/generate-command-config-schema.mjs +273 -0
  345. package/scripts/generate-commands-catalog.mjs +308 -0
  346. package/scripts/generate-module-agents.mjs +631 -0
  347. package/scripts/generate-seo-satellite-pages.mjs +400 -0
  348. package/scripts/github-deploy-notify.mjs +174 -0
  349. package/scripts/github-release-notify.mjs +219 -0
  350. package/scripts/release.sh +599 -0
  351. package/scripts/run-codeql-local.sh +116 -0
  352. package/scripts/run-prettier-all.mjs +25 -0
  353. package/scripts/security-smoketest.mjs +581 -0
  354. package/scripts/sticker-catalog-loadtest.mjs +210 -0
  355. package/scripts/sticker-worker-task.mjs +119 -0
  356. package/scripts/sync-readme-snapshot.mjs +133 -0
  357. package/scripts/validate-command-config-schema.mjs +130 -0
  358. package/scripts/validate-command-configs.mjs +15 -0
  359. package/scripts/wiki-sync.sh +191 -0
  360. package/server/auth/googleWebAuth/googleWebAuthRuntime.js +62 -0
  361. package/server/auth/googleWebAuth/googleWebAuthService.js +807 -0
  362. package/server/auth/jwt/webJwtService.js +147 -0
  363. package/server/auth/stickerCatalogAuthContext.js +165 -0
  364. package/server/auth/termsAcceptance/termsAcceptanceHandler.js +189 -0
  365. package/server/auth/userPassword/index.js +14 -0
  366. package/server/auth/userPassword/userPasswordAuthService.js +422 -0
  367. package/server/auth/userPassword/userPasswordCrypto.js +199 -0
  368. package/server/auth/userPassword/userPasswordCrypto.test.js +76 -0
  369. package/server/auth/userPassword/userPasswordRecoveryService.js +728 -0
  370. package/server/auth/validation/authSchemas.js +236 -0
  371. package/server/auth/webAccount/webAccountHandlers.js +1434 -0
  372. package/server/controllers/admin/adminBanService.js +138 -0
  373. package/server/controllers/admin/adminPanelHandlers.js +2083 -0
  374. package/server/controllers/admin/stickerCatalogAdminContext.js +17 -0
  375. package/server/controllers/admin/systemAdminController.js +201 -0
  376. package/server/controllers/email/emailAutomationController.js +239 -0
  377. package/server/controllers/metricsController.js +21 -0
  378. package/server/controllers/seo/stickerCatalogSeoContext.js +514 -0
  379. package/server/controllers/sticker/nonCatalogHandlers.js +303 -0
  380. package/server/controllers/sticker/stickerCatalogController.js +4700 -0
  381. package/server/controllers/system/contactController.js +115 -0
  382. package/server/controllers/system/githubController.js +137 -0
  383. package/server/controllers/system/stickerCatalogSystemContext.js +758 -0
  384. package/server/controllers/system/storageController.js +154 -0
  385. package/server/controllers/system/systemController.js +135 -0
  386. package/server/controllers/system/systemMetricsController.js +156 -0
  387. package/server/controllers/system/visitController.js +90 -0
  388. package/server/controllers/userController.js +145 -0
  389. package/server/email/emailAutomationRuntime.js +225 -0
  390. package/server/email/emailAutomationService.js +125 -0
  391. package/server/email/emailOutboxRepository.js +282 -0
  392. package/server/email/emailTemplateService.js +480 -0
  393. package/server/email/emailTransportService.js +156 -0
  394. package/server/http/clientIp.js +95 -0
  395. package/server/http/httpRequestUtils.js +262 -0
  396. package/server/http/httpRequestUtils.test.js +80 -0
  397. package/server/http/httpServer.js +180 -0
  398. package/server/http/requestContext.js +20 -0
  399. package/server/http/siteRoutingUtils.js +87 -0
  400. package/server/index.js +1 -0
  401. package/server/middleware/cachePolicy.js +26 -0
  402. package/server/middleware/cachePolicyHelpers.js +1 -0
  403. package/server/middleware/endpointRateLimit.js +181 -0
  404. package/server/middleware/rateLimit.js +70 -0
  405. package/server/middleware/requireAdminAuth.js +48 -0
  406. package/server/middleware/securityHeaders.js +97 -0
  407. package/server/routes/admin/systemAdminRouter.js +64 -0
  408. package/server/routes/email/emailAutomationRouter.js +46 -0
  409. package/server/routes/health/healthRouter.js +41 -0
  410. package/server/routes/indexRouter.js +234 -0
  411. package/server/routes/metrics/metricsRouter.js +58 -0
  412. package/server/routes/static/staticPageRouter.js +134 -0
  413. package/server/routes/sticker/catalogHandlers/catalogAdminHttp.js +105 -0
  414. package/server/routes/sticker/catalogHandlers/catalogAuthHttp.js +77 -0
  415. package/server/routes/sticker/catalogHandlers/catalogPublicHttp.js +120 -0
  416. package/server/routes/sticker/catalogHandlers/catalogUploadHttp.js +83 -0
  417. package/server/routes/sticker/catalogRouter.js +77 -0
  418. package/server/routes/sticker/stickerApiRouter.js +84 -0
  419. package/server/routes/sticker/stickerDataRouter.js +145 -0
  420. package/server/routes/sticker/stickerSiteRouter.js +43 -0
  421. package/server/routes/user/userApiPaths.js +66 -0
  422. package/server/routes/user/userRouter.js +65 -0
  423. package/server/utils/safePath.js +26 -0
  424. package/utils/logger/loggerModule.js +35 -0
  425. package/vite.config.mjs +38 -0
@@ -0,0 +1,1288 @@
1
+ :root {
2
+ --bg: #0f172a;
3
+ --bg-soft: #111827;
4
+ --card: #1e293b;
5
+ --card-soft: #111827;
6
+ --line: rgba(255, 255, 255, 0.05);
7
+ --line-strong: rgba(255, 255, 255, 0.12);
8
+ --accent: #2563eb;
9
+ --accent-soft: rgba(37, 99, 235, 0.14);
10
+ --danger: #f43f5e;
11
+ --danger-soft: rgba(244, 63, 94, 0.14);
12
+ --warning: #f59e0b;
13
+ --warning-soft: rgba(245, 158, 11, 0.12);
14
+ --text: #f8fafc;
15
+ --text-soft: #94a3b8;
16
+ --text-muted: #64748b;
17
+ --radius-sm: 10px;
18
+ --radius-md: 14px;
19
+ --radius-lg: 18px;
20
+ --shadow-1: 0 1px 0 rgba(255, 255, 255, 0.05) inset;
21
+ --shadow-2: 0 12px 30px rgba(2, 6, 23, 0.28);
22
+ --transition: 150ms ease;
23
+ }
24
+
25
+ * {
26
+ box-sizing: border-box;
27
+ }
28
+
29
+ html,
30
+ body {
31
+ margin: 0;
32
+ min-height: 100%;
33
+ }
34
+
35
+ body {
36
+ font-family:
37
+ 'Manrope',
38
+ ui-sans-serif,
39
+ system-ui,
40
+ -apple-system,
41
+ 'Segoe UI',
42
+ sans-serif;
43
+ background: radial-gradient(1300px 660px at 12% -12%, rgba(37, 99, 235, 0.14), transparent 52%), radial-gradient(900px 500px at 92% -18%, rgba(59, 130, 246, 0.1), transparent 55%), var(--bg);
44
+ color: var(--text);
45
+ line-height: 1.4;
46
+ }
47
+
48
+ a {
49
+ color: var(--accent);
50
+ }
51
+
52
+ a:hover {
53
+ color: #7c3aed;
54
+ }
55
+
56
+ button,
57
+ input,
58
+ select,
59
+ textarea {
60
+ font: inherit;
61
+ }
62
+
63
+ button,
64
+ input,
65
+ textarea,
66
+ a {
67
+ -webkit-tap-highlight-color: rgba(37, 99, 235, 0.16);
68
+ }
69
+
70
+ button:focus-visible,
71
+ input:focus-visible,
72
+ a:focus-visible {
73
+ outline: 2px solid rgba(37, 99, 235, 0.62);
74
+ outline-offset: 2px;
75
+ }
76
+
77
+ .admin-app {
78
+ min-height: 100dvh;
79
+ }
80
+
81
+ .topbar {
82
+ position: fixed;
83
+ top: 0;
84
+ left: 0;
85
+ right: 0;
86
+ z-index: 70;
87
+ border-bottom: 1px solid var(--line);
88
+ backdrop-filter: blur(12px);
89
+ background: rgba(11, 18, 32, 0.86);
90
+ }
91
+
92
+ .topbar-inner {
93
+ max-width: 1440px;
94
+ margin: 0 auto;
95
+ min-height: 64px;
96
+ padding: 10px 20px;
97
+ display: flex;
98
+ justify-content: space-between;
99
+ align-items: center;
100
+ gap: 14px;
101
+ }
102
+
103
+ .topbar-left,
104
+ .topbar-actions {
105
+ min-width: 0;
106
+ display: flex;
107
+ align-items: center;
108
+ gap: 10px;
109
+ }
110
+
111
+ .brand-dot {
112
+ width: 10px;
113
+ height: 10px;
114
+ border-radius: 999px;
115
+ background: var(--accent);
116
+ box-shadow: 0 0 0 5px rgba(37, 99, 235, 0.16);
117
+ }
118
+
119
+ .brand-title {
120
+ margin: 0;
121
+ font-size: 13px;
122
+ font-weight: 800;
123
+ letter-spacing: 0.08em;
124
+ text-transform: uppercase;
125
+ }
126
+
127
+ .brand-sub {
128
+ margin: 2px 0 0;
129
+ color: var(--text-soft);
130
+ font-size: 11px;
131
+ }
132
+
133
+ .user-chip {
134
+ display: inline-flex;
135
+ align-items: center;
136
+ max-width: 240px;
137
+ height: 34px;
138
+ padding: 0 12px;
139
+ border-radius: 999px;
140
+ border: 1px solid var(--line);
141
+ background: rgba(15, 23, 42, 0.7);
142
+ color: var(--text);
143
+ font-size: 12px;
144
+ font-weight: 600;
145
+ white-space: nowrap;
146
+ overflow: hidden;
147
+ text-overflow: ellipsis;
148
+ }
149
+
150
+ .layout-wrap {
151
+ max-width: 1440px;
152
+ margin: 0 auto;
153
+ padding: 84px 20px 22px;
154
+ display: grid;
155
+ grid-template-columns: 250px minmax(0, 1fr);
156
+ gap: 18px;
157
+ min-width: 0;
158
+ }
159
+
160
+ .sidebar {
161
+ min-width: 0;
162
+ position: sticky;
163
+ top: 84px;
164
+ align-self: start;
165
+ border-radius: var(--radius-lg);
166
+ border: 1px solid var(--line);
167
+ background: linear-gradient(180deg, rgba(17, 26, 43, 0.95), rgba(15, 23, 42, 0.94));
168
+ box-shadow: var(--shadow-1), var(--shadow-2);
169
+ padding: 14px;
170
+ }
171
+
172
+ .nav-group {
173
+ display: grid;
174
+ gap: 8px;
175
+ }
176
+
177
+ .nav-item {
178
+ width: 100%;
179
+ border: 1px solid transparent;
180
+ background: rgba(15, 23, 42, 0.65);
181
+ color: var(--text-soft);
182
+ border-radius: 12px;
183
+ min-height: 42px;
184
+ padding: 0 12px;
185
+ display: flex;
186
+ align-items: center;
187
+ justify-content: space-between;
188
+ gap: 8px;
189
+ font-size: 13px;
190
+ font-weight: 700;
191
+ text-align: left;
192
+ cursor: pointer;
193
+ transition:
194
+ border-color var(--transition),
195
+ color var(--transition),
196
+ background-color var(--transition),
197
+ transform var(--transition);
198
+ }
199
+
200
+ .nav-item:hover {
201
+ border-color: rgba(37, 99, 235, 0.28);
202
+ color: var(--text);
203
+ }
204
+
205
+ .nav-item.active {
206
+ border-color: rgba(37, 99, 235, 0.5);
207
+ color: #dbeafe;
208
+ background: rgba(37, 99, 235, 0.18);
209
+ }
210
+
211
+ .nav-count {
212
+ border-radius: 999px;
213
+ border: 1px solid var(--line);
214
+ background: rgba(11, 18, 32, 0.6);
215
+ color: var(--text-soft);
216
+ padding: 2px 8px;
217
+ font-size: 11px;
218
+ font-weight: 700;
219
+ }
220
+
221
+ .sidebar-footer {
222
+ margin-top: 14px;
223
+ padding-top: 14px;
224
+ border-top: 1px solid var(--line);
225
+ display: grid;
226
+ gap: 8px;
227
+ }
228
+
229
+ .main {
230
+ min-width: 0;
231
+ }
232
+
233
+ .stack {
234
+ min-width: 0;
235
+ display: grid;
236
+ gap: 16px;
237
+ }
238
+
239
+ .metrics-grid {
240
+ display: grid;
241
+ gap: 12px;
242
+ grid-template-columns: repeat(4, minmax(0, 1fr));
243
+ }
244
+
245
+ .metric-card {
246
+ border-radius: var(--radius-md);
247
+ border: 1px solid var(--line);
248
+ background: linear-gradient(180deg, rgba(17, 26, 43, 0.95), rgba(14, 23, 38, 0.9));
249
+ box-shadow: var(--shadow-1);
250
+ padding: 14px;
251
+ min-width: 0;
252
+ transition:
253
+ transform var(--transition),
254
+ border-color var(--transition),
255
+ background-color var(--transition);
256
+ }
257
+
258
+ .metric-card:hover {
259
+ transform: translateY(-1px);
260
+ border-color: rgba(148, 163, 184, 0.24);
261
+ }
262
+
263
+ .metric-label {
264
+ margin: 0;
265
+ font-size: 10px;
266
+ letter-spacing: 0.08em;
267
+ text-transform: uppercase;
268
+ color: var(--text-soft);
269
+ font-weight: 700;
270
+ }
271
+
272
+ .metric-value {
273
+ margin: 4px 0 8px;
274
+ font-size: clamp(1.36rem, 1.8vw, 1.82rem);
275
+ line-height: 1.15;
276
+ font-weight: 800;
277
+ letter-spacing: -0.02em;
278
+ }
279
+
280
+ .metric-foot {
281
+ display: flex;
282
+ align-items: flex-end;
283
+ justify-content: space-between;
284
+ gap: 8px;
285
+ }
286
+
287
+ .metric-trend {
288
+ margin: 0;
289
+ font-size: 11px;
290
+ color: var(--text-soft);
291
+ }
292
+
293
+ .trend-up {
294
+ color: #2563eb;
295
+ }
296
+
297
+ .trend-down {
298
+ color: #fda4af;
299
+ }
300
+
301
+ .trend-neutral {
302
+ color: var(--text-soft);
303
+ }
304
+
305
+ .sparkline {
306
+ display: flex;
307
+ align-items: flex-end;
308
+ gap: 3px;
309
+ }
310
+
311
+ .sparkbar {
312
+ width: 5px;
313
+ border-radius: 999px;
314
+ background: linear-gradient(180deg, #60a5fa, #6d28d9);
315
+ opacity: 0.92;
316
+ }
317
+
318
+ .tabs-strip {
319
+ overflow-x: auto;
320
+ display: flex;
321
+ gap: 8px;
322
+ padding: 5px;
323
+ border-radius: 14px;
324
+ border: 1px solid var(--line);
325
+ background: rgba(15, 23, 42, 0.62);
326
+ }
327
+
328
+ .tabs-strip::-webkit-scrollbar,
329
+ .mobile-list::-webkit-scrollbar,
330
+ .table-shell::-webkit-scrollbar,
331
+ .detail-list::-webkit-scrollbar,
332
+ .upload-grid::-webkit-scrollbar,
333
+ .code-block::-webkit-scrollbar,
334
+ .drawer-panel::-webkit-scrollbar {
335
+ height: 8px;
336
+ width: 8px;
337
+ }
338
+
339
+ .tabs-strip::-webkit-scrollbar-thumb,
340
+ .mobile-list::-webkit-scrollbar-thumb,
341
+ .table-shell::-webkit-scrollbar-thumb,
342
+ .detail-list::-webkit-scrollbar-thumb,
343
+ .upload-grid::-webkit-scrollbar-thumb,
344
+ .code-block::-webkit-scrollbar-thumb,
345
+ .drawer-panel::-webkit-scrollbar-thumb {
346
+ background: rgba(148, 163, 184, 0.36);
347
+ border-radius: 999px;
348
+ }
349
+
350
+ .tab-btn {
351
+ border: 1px solid transparent;
352
+ background: transparent;
353
+ color: var(--text-soft);
354
+ border-radius: 10px;
355
+ padding: 9px 12px;
356
+ min-height: 38px;
357
+ font-size: 12px;
358
+ font-weight: 700;
359
+ white-space: nowrap;
360
+ cursor: pointer;
361
+ transition:
362
+ background-color var(--transition),
363
+ border-color var(--transition),
364
+ color var(--transition);
365
+ }
366
+
367
+ .tab-btn:hover {
368
+ color: var(--text);
369
+ background: rgba(30, 41, 59, 0.64);
370
+ }
371
+
372
+ .tab-btn.active {
373
+ border-color: rgba(37, 99, 235, 0.46);
374
+ background: rgba(37, 99, 235, 0.16);
375
+ color: #dcfffa;
376
+ }
377
+
378
+ .panel {
379
+ min-width: 0;
380
+ border-radius: var(--radius-lg);
381
+ border: 1px solid var(--line);
382
+ background: linear-gradient(180deg, rgba(17, 26, 43, 0.95), rgba(14, 23, 38, 0.92));
383
+ box-shadow: var(--shadow-1);
384
+ padding: 14px;
385
+ }
386
+
387
+ .panel.inner {
388
+ padding: 12px;
389
+ background: linear-gradient(180deg, rgba(22, 34, 56, 0.82), rgba(15, 23, 42, 0.76));
390
+ }
391
+
392
+ .panel-head {
393
+ min-width: 0;
394
+ display: flex;
395
+ justify-content: space-between;
396
+ align-items: flex-start;
397
+ gap: 12px;
398
+ margin-bottom: 12px;
399
+ }
400
+
401
+ .panel-head.slim {
402
+ margin-bottom: 10px;
403
+ }
404
+
405
+ .panel-title {
406
+ margin: 0;
407
+ font-size: clamp(1.02rem, 1.5vw, 1.52rem);
408
+ font-weight: 800;
409
+ letter-spacing: -0.015em;
410
+ }
411
+
412
+ .panel-head.slim .panel-title {
413
+ font-size: 1.02rem;
414
+ }
415
+
416
+ .panel-desc {
417
+ margin: 3px 0 0;
418
+ color: var(--text-soft);
419
+ font-size: 12px;
420
+ }
421
+
422
+ .section-grid {
423
+ min-width: 0;
424
+ display: grid;
425
+ gap: 14px;
426
+ }
427
+
428
+ .section-grid.two-col {
429
+ grid-template-columns: repeat(2, minmax(0, 1fr));
430
+ }
431
+
432
+ .search-form {
433
+ display: flex;
434
+ align-items: center;
435
+ gap: 8px;
436
+ width: min(100%, 520px);
437
+ }
438
+
439
+ .search-form.compact {
440
+ width: min(100%, 420px);
441
+ }
442
+
443
+ .search-input {
444
+ width: 100%;
445
+ min-width: 0;
446
+ height: 40px;
447
+ border-radius: 11px;
448
+ border: 1px solid var(--line-strong);
449
+ background: rgba(15, 23, 42, 0.88);
450
+ color: var(--text);
451
+ padding: 0 12px;
452
+ transition:
453
+ border-color var(--transition),
454
+ background-color var(--transition),
455
+ box-shadow var(--transition);
456
+ }
457
+
458
+ .search-input::placeholder {
459
+ color: #6b7c93;
460
+ }
461
+
462
+ .search-input:hover {
463
+ border-color: rgba(148, 163, 184, 0.3);
464
+ }
465
+
466
+ .search-input:focus-visible {
467
+ border-color: rgba(37, 99, 235, 0.64);
468
+ box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.14);
469
+ }
470
+
471
+ .primary-btn,
472
+ .outline-btn,
473
+ .danger-btn,
474
+ .subtle-btn,
475
+ .ghost-btn,
476
+ .icon-btn,
477
+ .menu-trigger {
478
+ appearance: none;
479
+ border: 1px solid transparent;
480
+ border-radius: 10px;
481
+ height: 38px;
482
+ display: inline-flex;
483
+ align-items: center;
484
+ justify-content: center;
485
+ gap: 6px;
486
+ padding: 0 12px;
487
+ cursor: pointer;
488
+ text-decoration: none;
489
+ font-size: 12px;
490
+ font-weight: 700;
491
+ transition:
492
+ background-color var(--transition),
493
+ border-color var(--transition),
494
+ color var(--transition),
495
+ transform var(--transition),
496
+ opacity var(--transition);
497
+ }
498
+
499
+ .primary-btn {
500
+ background: var(--accent);
501
+ color: #07131e;
502
+ border-color: transparent;
503
+ }
504
+
505
+ .primary-btn:hover:not(:disabled) {
506
+ background: #2563eb;
507
+ transform: translateY(-1px);
508
+ }
509
+
510
+ .outline-btn,
511
+ .subtle-btn,
512
+ .ghost-btn {
513
+ border-color: var(--line-strong);
514
+ color: var(--text);
515
+ background: rgba(15, 23, 42, 0.76);
516
+ }
517
+
518
+ .outline-btn:hover:not(:disabled),
519
+ .subtle-btn:hover:not(:disabled),
520
+ .ghost-btn:hover:not(:disabled) {
521
+ border-color: rgba(148, 163, 184, 0.35);
522
+ background: rgba(30, 41, 59, 0.84);
523
+ }
524
+
525
+ .danger-btn,
526
+ .ghost-btn.danger,
527
+ .subtle-btn.danger,
528
+ .row-menu-item.danger {
529
+ border-color: rgba(244, 63, 94, 0.42);
530
+ color: #fecdd3;
531
+ background: rgba(127, 29, 29, 0.12);
532
+ }
533
+
534
+ .danger-btn:hover:not(:disabled),
535
+ .ghost-btn.danger:hover:not(:disabled),
536
+ .subtle-btn.danger:hover:not(:disabled),
537
+ .row-menu-item.danger:hover:not(:disabled) {
538
+ background: rgba(244, 63, 94, 0.18);
539
+ border-color: rgba(244, 63, 94, 0.58);
540
+ }
541
+
542
+ .icon-btn {
543
+ width: 36px;
544
+ padding: 0;
545
+ border-color: var(--line-strong);
546
+ background: rgba(15, 23, 42, 0.8);
547
+ color: var(--text-soft);
548
+ }
549
+
550
+ .icon-btn:hover {
551
+ color: var(--text);
552
+ background: rgba(30, 41, 59, 0.88);
553
+ }
554
+
555
+ button:disabled,
556
+ a[aria-disabled='true'] {
557
+ opacity: 0.55;
558
+ cursor: not-allowed;
559
+ }
560
+
561
+ .table-shell {
562
+ min-width: 0;
563
+ overflow: auto;
564
+ border-radius: var(--radius-md);
565
+ border: 1px solid var(--line);
566
+ max-height: 420px;
567
+ background: rgba(11, 18, 32, 0.56);
568
+ }
569
+
570
+ .data-table {
571
+ width: 100%;
572
+ min-width: 620px;
573
+ border-collapse: collapse;
574
+ table-layout: fixed;
575
+ }
576
+
577
+ .data-table thead {
578
+ position: sticky;
579
+ top: 0;
580
+ z-index: 2;
581
+ background: rgba(17, 26, 43, 0.96);
582
+ }
583
+
584
+ .data-table th {
585
+ text-align: left;
586
+ font-size: 11px;
587
+ color: var(--text-soft);
588
+ letter-spacing: 0.045em;
589
+ text-transform: uppercase;
590
+ font-weight: 700;
591
+ padding: 10px 12px;
592
+ border-bottom: 1px solid var(--line);
593
+ white-space: nowrap;
594
+ }
595
+
596
+ .data-table td {
597
+ padding: 10px 12px;
598
+ border-bottom: 1px solid rgba(148, 163, 184, 0.08);
599
+ vertical-align: top;
600
+ font-size: 12px;
601
+ color: var(--text);
602
+ min-width: 0;
603
+ }
604
+
605
+ .data-table tbody tr {
606
+ transition: background-color var(--transition);
607
+ }
608
+
609
+ .data-table tbody tr:hover {
610
+ background: rgba(30, 41, 59, 0.34);
611
+ }
612
+
613
+ .data-table tr:last-child td {
614
+ border-bottom: 0;
615
+ }
616
+
617
+ .menu-wrap {
618
+ position: relative;
619
+ display: inline-flex;
620
+ }
621
+
622
+ .menu-trigger {
623
+ width: 34px;
624
+ padding: 0;
625
+ border-radius: 10px;
626
+ background: rgba(15, 23, 42, 0.8);
627
+ border-color: var(--line-strong);
628
+ color: var(--text-soft);
629
+ }
630
+
631
+ .menu-trigger:hover {
632
+ color: var(--text);
633
+ }
634
+
635
+ .row-menu {
636
+ position: absolute;
637
+ top: calc(100% + 6px);
638
+ right: 0;
639
+ width: max-content;
640
+ min-width: 178px;
641
+ z-index: 35;
642
+ border-radius: 12px;
643
+ border: 1px solid var(--line-strong);
644
+ background: rgba(15, 23, 42, 0.96);
645
+ backdrop-filter: blur(8px);
646
+ box-shadow: 0 14px 36px rgba(2, 6, 23, 0.48);
647
+ padding: 6px;
648
+ display: grid;
649
+ gap: 4px;
650
+ }
651
+
652
+ .row-menu-item {
653
+ width: 100%;
654
+ min-height: 34px;
655
+ border-radius: 8px;
656
+ border: 1px solid transparent;
657
+ background: transparent;
658
+ color: var(--text);
659
+ font-size: 12px;
660
+ font-weight: 600;
661
+ text-align: left;
662
+ display: inline-flex;
663
+ align-items: center;
664
+ padding: 0 10px;
665
+ text-decoration: none;
666
+ }
667
+
668
+ .row-menu-item:hover {
669
+ background: rgba(51, 65, 85, 0.48);
670
+ }
671
+
672
+ .row-title {
673
+ margin: 0;
674
+ font-size: 13px;
675
+ line-height: 1.35;
676
+ font-weight: 700;
677
+ }
678
+
679
+ .row-sub {
680
+ margin: 2px 0 0;
681
+ font-size: 12px;
682
+ color: #b6c2d3;
683
+ }
684
+
685
+ .row-meta {
686
+ margin: 2px 0 0;
687
+ font-size: 11px;
688
+ color: var(--text-muted);
689
+ }
690
+
691
+ .badge-row {
692
+ margin-top: 7px;
693
+ display: flex;
694
+ align-items: center;
695
+ flex-wrap: wrap;
696
+ gap: 6px;
697
+ }
698
+
699
+ .status-badge {
700
+ display: inline-flex;
701
+ align-items: center;
702
+ border-radius: 999px;
703
+ padding: 3px 9px;
704
+ border: 1px solid var(--line-strong);
705
+ background: rgba(51, 65, 85, 0.22);
706
+ font-size: 10px;
707
+ font-weight: 700;
708
+ color: var(--text-soft);
709
+ text-transform: lowercase;
710
+ }
711
+
712
+ .status-success {
713
+ border-color: rgba(37, 99, 235, 0.36);
714
+ background: rgba(37, 99, 235, 0.14);
715
+ color: #c4b5fd;
716
+ }
717
+
718
+ .status-danger {
719
+ border-color: rgba(244, 63, 94, 0.45);
720
+ background: rgba(244, 63, 94, 0.15);
721
+ color: #fecdd3;
722
+ }
723
+
724
+ .status-warning {
725
+ border-color: rgba(245, 158, 11, 0.45);
726
+ background: rgba(245, 158, 11, 0.14);
727
+ color: #fcd34d;
728
+ }
729
+
730
+ .status-neutral {
731
+ border-color: var(--line-strong);
732
+ background: rgba(71, 85, 105, 0.14);
733
+ color: #cbd5e1;
734
+ }
735
+
736
+ .mono {
737
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
738
+ }
739
+
740
+ .muted {
741
+ color: var(--text-soft);
742
+ }
743
+
744
+ .break-all {
745
+ word-break: break-all;
746
+ }
747
+
748
+ .break-words {
749
+ word-break: break-word;
750
+ overflow-wrap: anywhere;
751
+ }
752
+
753
+ .pager {
754
+ display: flex;
755
+ justify-content: space-between;
756
+ align-items: center;
757
+ gap: 8px;
758
+ padding-top: 10px;
759
+ }
760
+
761
+ .pager-meta {
762
+ color: var(--text-soft);
763
+ font-size: 11px;
764
+ text-align: center;
765
+ flex: 1;
766
+ }
767
+
768
+ .mobile-list {
769
+ display: grid;
770
+ gap: 10px;
771
+ max-height: 520px;
772
+ overflow: auto;
773
+ min-width: 0;
774
+ }
775
+
776
+ .mobile-card {
777
+ min-width: 0;
778
+ border-radius: 12px;
779
+ border: 1px solid var(--line);
780
+ background: rgba(15, 23, 42, 0.76);
781
+ padding: 10px;
782
+ }
783
+
784
+ .mobile-card-foot {
785
+ margin-top: 8px;
786
+ display: flex;
787
+ justify-content: space-between;
788
+ align-items: center;
789
+ gap: 8px;
790
+ }
791
+
792
+ .selected-pack-head {
793
+ display: flex;
794
+ justify-content: space-between;
795
+ align-items: flex-start;
796
+ gap: 12px;
797
+ padding: 12px;
798
+ border-radius: 12px;
799
+ border: 1px solid var(--line);
800
+ background: rgba(15, 23, 42, 0.68);
801
+ }
802
+
803
+ .selected-pack-actions {
804
+ display: flex;
805
+ flex-wrap: wrap;
806
+ gap: 8px;
807
+ }
808
+
809
+ .detail-list {
810
+ margin-top: 10px;
811
+ display: grid;
812
+ gap: 8px;
813
+ max-height: 520px;
814
+ overflow: auto;
815
+ }
816
+
817
+ .detail-item {
818
+ min-width: 0;
819
+ display: grid;
820
+ grid-template-columns: 52px minmax(0, 1fr) auto;
821
+ gap: 10px;
822
+ border: 1px solid var(--line);
823
+ border-radius: 12px;
824
+ padding: 8px;
825
+ background: rgba(15, 23, 42, 0.7);
826
+ }
827
+
828
+ .detail-thumb {
829
+ width: 52px;
830
+ height: 52px;
831
+ border-radius: 10px;
832
+ border: 1px solid var(--line);
833
+ object-fit: cover;
834
+ background: rgba(15, 23, 42, 0.95);
835
+ }
836
+
837
+ .detail-content {
838
+ min-width: 0;
839
+ }
840
+
841
+ .detail-actions {
842
+ display: grid;
843
+ gap: 7px;
844
+ align-content: start;
845
+ }
846
+
847
+ .form-grid {
848
+ display: grid;
849
+ gap: 8px;
850
+ }
851
+
852
+ .upload-grid {
853
+ display: grid;
854
+ grid-template-columns: repeat(2, minmax(0, 1fr));
855
+ gap: 10px;
856
+ }
857
+
858
+ .upload-card {
859
+ min-width: 0;
860
+ border-radius: 12px;
861
+ border: 1px solid var(--line);
862
+ background: rgba(15, 23, 42, 0.75);
863
+ padding: 10px;
864
+ display: grid;
865
+ gap: 10px;
866
+ }
867
+
868
+ .upload-card-head {
869
+ display: flex;
870
+ align-items: flex-start;
871
+ justify-content: space-between;
872
+ gap: 10px;
873
+ }
874
+
875
+ .progress-wrap {
876
+ display: grid;
877
+ grid-template-columns: minmax(0, 1fr) auto;
878
+ gap: 8px;
879
+ align-items: center;
880
+ }
881
+
882
+ .progress-track {
883
+ width: 100%;
884
+ height: 8px;
885
+ border-radius: 999px;
886
+ background: rgba(51, 65, 85, 0.58);
887
+ overflow: hidden;
888
+ }
889
+
890
+ .progress-bar {
891
+ display: block;
892
+ height: 100%;
893
+ background: linear-gradient(90deg, #2563eb, #7c3aed);
894
+ }
895
+
896
+ .progress-meta {
897
+ font-size: 11px;
898
+ color: var(--text-soft);
899
+ }
900
+
901
+ .upload-meta {
902
+ display: flex;
903
+ justify-content: space-between;
904
+ align-items: center;
905
+ gap: 8px;
906
+ color: var(--text-soft);
907
+ font-size: 11px;
908
+ }
909
+
910
+ .upload-actions {
911
+ display: flex;
912
+ flex-wrap: wrap;
913
+ gap: 8px;
914
+ }
915
+
916
+ .upload-actions .menu-wrap {
917
+ margin-left: auto;
918
+ }
919
+
920
+ .kv-grid {
921
+ display: grid;
922
+ gap: 8px;
923
+ }
924
+
925
+ .kv-item {
926
+ border-radius: 10px;
927
+ border: 1px solid var(--line);
928
+ background: rgba(15, 23, 42, 0.66);
929
+ padding: 10px;
930
+ display: flex;
931
+ justify-content: space-between;
932
+ align-items: center;
933
+ gap: 8px;
934
+ }
935
+
936
+ .kv-key {
937
+ color: var(--text-soft);
938
+ font-size: 12px;
939
+ }
940
+
941
+ .kv-value {
942
+ font-size: 12px;
943
+ font-weight: 700;
944
+ color: var(--text);
945
+ text-align: right;
946
+ }
947
+
948
+ .code-block {
949
+ margin: 0;
950
+ border-radius: 12px;
951
+ border: 1px solid var(--line);
952
+ background: rgba(11, 18, 32, 0.7);
953
+ padding: 12px;
954
+ color: #cbd5e1;
955
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
956
+ font-size: 11px;
957
+ max-height: 340px;
958
+ overflow: auto;
959
+ }
960
+
961
+ .account-box {
962
+ border-radius: 12px;
963
+ border: 1px solid rgba(37, 99, 235, 0.32);
964
+ background: rgba(37, 99, 235, 0.1);
965
+ padding: 10px;
966
+ }
967
+
968
+ .account-box.warning {
969
+ border-color: rgba(245, 158, 11, 0.4);
970
+ background: rgba(245, 158, 11, 0.12);
971
+ }
972
+
973
+ .google-login-box {
974
+ margin-top: 10px;
975
+ }
976
+
977
+ .google-login-slot {
978
+ min-height: 42px;
979
+ }
980
+
981
+ .hint {
982
+ margin: 0;
983
+ font-size: 11px;
984
+ color: var(--text-soft);
985
+ }
986
+
987
+ .hint.warning {
988
+ color: #fcd34d;
989
+ }
990
+
991
+ .inline-alert {
992
+ margin-bottom: 12px;
993
+ border-radius: 12px;
994
+ border: 1px solid rgba(244, 63, 94, 0.38);
995
+ background: rgba(127, 29, 29, 0.22);
996
+ color: #fecdd3;
997
+ padding: 9px 11px;
998
+ font-size: 12px;
999
+ }
1000
+
1001
+ .empty,
1002
+ .empty-box {
1003
+ color: var(--text-soft);
1004
+ text-align: center;
1005
+ font-size: 12px;
1006
+ }
1007
+
1008
+ .empty-box {
1009
+ border-radius: 12px;
1010
+ border: 1px dashed rgba(148, 163, 184, 0.26);
1011
+ padding: 18px 12px;
1012
+ }
1013
+
1014
+ .drawer {
1015
+ position: fixed;
1016
+ inset: 0;
1017
+ z-index: 80;
1018
+ }
1019
+
1020
+ .drawer-backdrop {
1021
+ position: absolute;
1022
+ inset: 0;
1023
+ background: rgba(2, 6, 23, 0.62);
1024
+ }
1025
+
1026
+ .drawer-panel {
1027
+ position: absolute;
1028
+ top: 0;
1029
+ bottom: 0;
1030
+ left: 0;
1031
+ width: min(84vw, 300px);
1032
+ border-right: 1px solid var(--line);
1033
+ background: rgba(11, 18, 32, 0.96);
1034
+ backdrop-filter: blur(12px);
1035
+ padding: 14px;
1036
+ overflow: auto;
1037
+ display: grid;
1038
+ grid-auto-rows: min-content;
1039
+ gap: 10px;
1040
+ }
1041
+
1042
+ .drawer-head {
1043
+ display: flex;
1044
+ justify-content: space-between;
1045
+ align-items: center;
1046
+ }
1047
+
1048
+ .toast-stack {
1049
+ position: fixed;
1050
+ top: 74px;
1051
+ right: 20px;
1052
+ z-index: 90;
1053
+ width: min(92vw, 400px);
1054
+ }
1055
+
1056
+ .toast {
1057
+ border-radius: 12px;
1058
+ border: 1px solid var(--line);
1059
+ padding: 11px 12px;
1060
+ font-size: 12px;
1061
+ font-weight: 600;
1062
+ box-shadow: 0 12px 34px rgba(2, 6, 23, 0.42);
1063
+ }
1064
+
1065
+ .toast.success {
1066
+ border-color: rgba(37, 99, 235, 0.42);
1067
+ color: #bff8f1;
1068
+ background: rgba(37, 99, 235, 0.16);
1069
+ }
1070
+
1071
+ .toast.danger {
1072
+ border-color: rgba(244, 63, 94, 0.45);
1073
+ color: #fecdd3;
1074
+ background: rgba(244, 63, 94, 0.16);
1075
+ }
1076
+
1077
+ .desktop-only {
1078
+ display: block;
1079
+ }
1080
+
1081
+ .mobile-only {
1082
+ display: none;
1083
+ }
1084
+
1085
+ .skeleton {
1086
+ position: relative;
1087
+ overflow: hidden;
1088
+ }
1089
+
1090
+ .skeleton::after {
1091
+ content: '';
1092
+ position: absolute;
1093
+ inset: 0;
1094
+ transform: translateX(-100%);
1095
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.05), transparent);
1096
+ animation: shimmer 1.2s infinite;
1097
+ }
1098
+
1099
+ .skeleton-line {
1100
+ height: 10px;
1101
+ border-radius: 999px;
1102
+ background: rgba(71, 85, 105, 0.45);
1103
+ margin-bottom: 8px;
1104
+ }
1105
+
1106
+ .w-30 {
1107
+ width: 30%;
1108
+ }
1109
+
1110
+ .w-50 {
1111
+ width: 50%;
1112
+ }
1113
+
1114
+ .w-60 {
1115
+ width: 60%;
1116
+ }
1117
+
1118
+ .w-80 {
1119
+ width: 80%;
1120
+ }
1121
+
1122
+ .w-85 {
1123
+ width: 85%;
1124
+ }
1125
+
1126
+ .w-90 {
1127
+ width: 90%;
1128
+ }
1129
+
1130
+ @keyframes shimmer {
1131
+ 100% {
1132
+ transform: translateX(100%);
1133
+ }
1134
+ }
1135
+
1136
+ @media (max-width: 1250px) {
1137
+ .metrics-grid {
1138
+ grid-template-columns: repeat(2, minmax(0, 1fr));
1139
+ }
1140
+
1141
+ .upload-grid {
1142
+ grid-template-columns: minmax(0, 1fr);
1143
+ }
1144
+ }
1145
+
1146
+ @media (max-width: 1024px) {
1147
+ .layout-wrap {
1148
+ grid-template-columns: minmax(0, 1fr);
1149
+ padding-top: 78px;
1150
+ }
1151
+
1152
+ .sidebar.desktop-only {
1153
+ display: none;
1154
+ }
1155
+
1156
+ .section-grid.two-col {
1157
+ grid-template-columns: minmax(0, 1fr);
1158
+ }
1159
+
1160
+ .topbar-actions .user-chip {
1161
+ max-width: 168px;
1162
+ }
1163
+
1164
+ .topbar-left .mobile-only {
1165
+ display: inline-flex !important;
1166
+ }
1167
+ }
1168
+
1169
+ @media (max-width: 768px) {
1170
+ .topbar-inner {
1171
+ padding-inline: 12px;
1172
+ min-height: 58px;
1173
+ }
1174
+
1175
+ .topbar-actions {
1176
+ gap: 6px;
1177
+ }
1178
+
1179
+ .topbar-actions .ghost-btn,
1180
+ .topbar-actions .user-chip {
1181
+ display: none;
1182
+ }
1183
+
1184
+ .layout-wrap {
1185
+ padding: 70px 10px 14px;
1186
+ gap: 12px;
1187
+ }
1188
+
1189
+ .stack {
1190
+ gap: 12px;
1191
+ }
1192
+
1193
+ .metrics-grid {
1194
+ grid-template-columns: minmax(0, 1fr);
1195
+ }
1196
+
1197
+ .panel {
1198
+ padding: 10px;
1199
+ border-radius: 14px;
1200
+ }
1201
+
1202
+ .panel-head {
1203
+ flex-direction: column;
1204
+ align-items: stretch;
1205
+ gap: 8px;
1206
+ }
1207
+
1208
+ .search-form,
1209
+ .search-form.compact {
1210
+ width: 100%;
1211
+ }
1212
+
1213
+ .search-form {
1214
+ flex-direction: column;
1215
+ align-items: stretch;
1216
+ }
1217
+
1218
+ .search-form .outline-btn,
1219
+ .search-form .primary-btn,
1220
+ .search-form .danger-btn,
1221
+ .search-form .subtle-btn {
1222
+ width: 100%;
1223
+ }
1224
+
1225
+ .selected-pack-head {
1226
+ flex-direction: column;
1227
+ }
1228
+
1229
+ .selected-pack-actions {
1230
+ width: 100%;
1231
+ }
1232
+
1233
+ .selected-pack-actions > * {
1234
+ flex: 1;
1235
+ justify-content: center;
1236
+ }
1237
+
1238
+ .detail-item {
1239
+ grid-template-columns: 44px minmax(0, 1fr);
1240
+ }
1241
+
1242
+ .detail-thumb {
1243
+ width: 44px;
1244
+ height: 44px;
1245
+ }
1246
+
1247
+ .detail-actions {
1248
+ grid-column: span 2;
1249
+ grid-template-columns: repeat(2, minmax(0, 1fr));
1250
+ }
1251
+
1252
+ .detail-actions .outline-btn,
1253
+ .detail-actions .danger-btn {
1254
+ width: 100%;
1255
+ justify-content: center;
1256
+ }
1257
+
1258
+ .desktop-only {
1259
+ display: none !important;
1260
+ }
1261
+
1262
+ .mobile-only {
1263
+ display: block !important;
1264
+ }
1265
+
1266
+ .pager {
1267
+ flex-wrap: wrap;
1268
+ }
1269
+
1270
+ .pager .subtle-btn {
1271
+ flex: 1;
1272
+ }
1273
+
1274
+ .toast-stack {
1275
+ top: 64px;
1276
+ right: 10px;
1277
+ }
1278
+ }
1279
+
1280
+ @media (prefers-reduced-motion: reduce) {
1281
+ *,
1282
+ *::before,
1283
+ *::after {
1284
+ animation: none !important;
1285
+ transition: none !important;
1286
+ scroll-behavior: auto !important;
1287
+ }
1288
+ }