@rynt/sdk 0.9.53

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 (332) hide show
  1. package/README.md +122 -0
  2. package/REGISTRIES.md +189 -0
  3. package/env.d.ts +11 -0
  4. package/host-shims.d.ts +30 -0
  5. package/package.json +88 -0
  6. package/src/extension-marketplace/api-types.ts +141 -0
  7. package/src/extension-marketplace/client.ts +296 -0
  8. package/src/extension-marketplace/index.ts +22 -0
  9. package/src/extension-marketplace/schemas.ts +178 -0
  10. package/src/extensions/ExtensionRoutePage.vue +17 -0
  11. package/src/extensions/context.ts +37 -0
  12. package/src/extensions/disabled-folder.ts +21 -0
  13. package/src/extensions/extension-expose-map.ts +5 -0
  14. package/src/extensions/extension-expose.ts +48 -0
  15. package/src/extensions/graph.ts +67 -0
  16. package/src/extensions/index.ts +251 -0
  17. package/src/extensions/invite-handler/types.ts +20 -0
  18. package/src/extensions/launcher-entities/create-launcher-entity.ts +25 -0
  19. package/src/extensions/launcher-entities/keys.ts +46 -0
  20. package/src/extensions/launcher-entities/launcher-entity-components.ts +177 -0
  21. package/src/extensions/launcher-entities/props-map.ts +69 -0
  22. package/src/extensions/launcher-entities/registry.ts +32 -0
  23. package/src/extensions/launcher-models/apis/accounts-contracts.ts +102 -0
  24. package/src/extensions/launcher-models/apis/launcher-model-apis.ts +553 -0
  25. package/src/extensions/launcher-models/keys.ts +23 -0
  26. package/src/extensions/launcher-models/public.ts +9 -0
  27. package/src/extensions/launcher-models/registry-core.ts +34 -0
  28. package/src/extensions/manifest-types.ts +22 -0
  29. package/src/extensions/manifest.ts +46 -0
  30. package/src/extensions/marketplace-open-key.ts +26 -0
  31. package/src/extensions/plugin-types.ts +44 -0
  32. package/src/extensions/plugin.ts +62 -0
  33. package/src/extensions/registries/bootstrap.ts +11 -0
  34. package/src/extensions/registries/builtins/account-provider.ts +6 -0
  35. package/src/extensions/registries/builtins/app-topbar-left-widgets.ts +6 -0
  36. package/src/extensions/registries/builtins/app-topbar-right-widgets.ts +6 -0
  37. package/src/extensions/registries/builtins/app-topbar-status-widgets.ts +6 -0
  38. package/src/extensions/registries/builtins/build-card-actions.ts +6 -0
  39. package/src/extensions/registries/builtins/build-card-after-meta.ts +6 -0
  40. package/src/extensions/registries/builtins/build-card-before-media.ts +6 -0
  41. package/src/extensions/registries/builtins/build-card-before-meta.ts +6 -0
  42. package/src/extensions/registries/builtins/build-card-footer-actions.ts +6 -0
  43. package/src/extensions/registries/builtins/build-detail-after-content.ts +6 -0
  44. package/src/extensions/registries/builtins/build-detail-before-content.ts +6 -0
  45. package/src/extensions/registries/builtins/build-detail-before-hero.ts +6 -0
  46. package/src/extensions/registries/builtins/build-detail-header-actions.ts +6 -0
  47. package/src/extensions/registries/builtins/build-detail-mod-row-actions.ts +6 -0
  48. package/src/extensions/registries/builtins/build-detail-resourcepack-row-actions.ts +6 -0
  49. package/src/extensions/registries/builtins/build-detail-right-column-bottom.ts +6 -0
  50. package/src/extensions/registries/builtins/build-detail-right-column-top.ts +6 -0
  51. package/src/extensions/registries/builtins/dialog-footer-actions.ts +6 -0
  52. package/src/extensions/registries/builtins/feed-after-content.ts +6 -0
  53. package/src/extensions/registries/builtins/feed-before-content.ts +6 -0
  54. package/src/extensions/registries/builtins/file-editor.ts +19 -0
  55. package/src/extensions/registries/builtins/friends-after-list.ts +6 -0
  56. package/src/extensions/registries/builtins/friends-before-list.ts +6 -0
  57. package/src/extensions/registries/builtins/index.ts +141 -0
  58. package/src/extensions/registries/builtins/invite-handler.ts +7 -0
  59. package/src/extensions/registries/builtins/library-after-content.ts +6 -0
  60. package/src/extensions/registries/builtins/library-before-content.ts +6 -0
  61. package/src/extensions/registries/builtins/loader.ts +8 -0
  62. package/src/extensions/registries/builtins/map-card-actions.ts +6 -0
  63. package/src/extensions/registries/builtins/map-card-after-meta.ts +6 -0
  64. package/src/extensions/registries/builtins/map-card-before-meta.ts +6 -0
  65. package/src/extensions/registries/builtins/map-card-footer-actions.ts +6 -0
  66. package/src/extensions/registries/builtins/map-detail-after-content.ts +6 -0
  67. package/src/extensions/registries/builtins/map-detail-before-content.ts +6 -0
  68. package/src/extensions/registries/builtins/map-detail-header-actions.ts +6 -0
  69. package/src/extensions/registries/builtins/markdown-editor-tiptap-extensions.ts +7 -0
  70. package/src/extensions/registries/builtins/markdown-editor-toolbar-actions.ts +6 -0
  71. package/src/extensions/registries/builtins/markdown-renderer-after-content.ts +6 -0
  72. package/src/extensions/registries/builtins/markdown-renderer-before-content.ts +6 -0
  73. package/src/extensions/registries/builtins/mod-details-footer-actions.ts +6 -0
  74. package/src/extensions/registries/builtins/mod-manage-actions.ts +6 -0
  75. package/src/extensions/registries/builtins/mod-provider.ts +5 -0
  76. package/src/extensions/registries/builtins/nav.ts +7 -0
  77. package/src/extensions/registries/builtins/page.ts +13 -0
  78. package/src/extensions/registries/builtins/projects-after-content.ts +6 -0
  79. package/src/extensions/registries/builtins/projects-before-content.ts +6 -0
  80. package/src/extensions/registries/builtins/resourcepack-manage-actions.ts +7 -0
  81. package/src/extensions/registries/builtins/server-card-actions.ts +6 -0
  82. package/src/extensions/registries/builtins/server-card-after-meta.ts +6 -0
  83. package/src/extensions/registries/builtins/server-card-before-meta.ts +6 -0
  84. package/src/extensions/registries/builtins/server-card-footer-actions.ts +6 -0
  85. package/src/extensions/registries/builtins/server-detail-after-content.ts +6 -0
  86. package/src/extensions/registries/builtins/server-detail-before-content.ts +6 -0
  87. package/src/extensions/registries/builtins/server-detail-header-actions.ts +6 -0
  88. package/src/extensions/registries/builtins/settings-after-sections.ts +6 -0
  89. package/src/extensions/registries/builtins/settings-before-sections.ts +6 -0
  90. package/src/extensions/registries/builtins/settings-section-widgets.ts +6 -0
  91. package/src/extensions/registries/builtins/shaderpack-manage-actions.ts +7 -0
  92. package/src/extensions/registries/builtins/shell.ts +5 -0
  93. package/src/extensions/registries/builtins/sidebar-after-content.ts +6 -0
  94. package/src/extensions/registries/builtins/sidebar-before-content.ts +6 -0
  95. package/src/extensions/registries/builtins/sidebar-footer-widgets.ts +6 -0
  96. package/src/extensions/registries/builtins/sidebar-header-widgets.ts +6 -0
  97. package/src/extensions/registries/builtins/sidebar.ts +11 -0
  98. package/src/extensions/registries/builtins/theme.ts +5 -0
  99. package/src/extensions/registries/builtins/user-card-after-meta.ts +6 -0
  100. package/src/extensions/registries/builtins/user-card-before-meta.ts +6 -0
  101. package/src/extensions/registries/builtins/user-menu-actions.ts +6 -0
  102. package/src/extensions/registries/builtins/user-menu-after-actions.ts +6 -0
  103. package/src/extensions/registries/builtins/user-menu-before-actions.ts +6 -0
  104. package/src/extensions/registries/builtins/user-strip.ts +5 -0
  105. package/src/extensions/registries/clear-extension-ui-registries.ts +15 -0
  106. package/src/extensions/registries/define-extension-registry.ts +58 -0
  107. package/src/extensions/registries/extension-host-api.ts +41 -0
  108. package/src/extensions/registries/extension-registry-api.ts +103 -0
  109. package/src/extensions/registries/extension-registry-payload-map.ts +9 -0
  110. package/src/extensions/registries/extension-scope.ts +41 -0
  111. package/src/extensions/registries/get-registry.ts +23 -0
  112. package/src/extensions/registries/index.ts +58 -0
  113. package/src/extensions/registries/manifest-rynt.ts +193 -0
  114. package/src/extensions/registries/registry-slot.ts +40 -0
  115. package/src/extensions/registries/registry-value-map.ts +89 -0
  116. package/src/extensions/registries/store.ts +206 -0
  117. package/src/extensions/resolve-extensions.ts +245 -0
  118. package/src/extensions/router-bridge.ts +103 -0
  119. package/src/extensions/session.ts +6 -0
  120. package/src/extensions/slug.ts +23 -0
  121. package/src/extensions/version.ts +147 -0
  122. package/src/host/extensions-composables.ts +33 -0
  123. package/src/host/extensions-init.ts +194 -0
  124. package/src/host/index.ts +11 -0
  125. package/src/host/launcher-models/index.ts +4 -0
  126. package/src/index.ts +229 -0
  127. package/src/minecraft-loader/base-loader.ts +102 -0
  128. package/src/minecraft-loader/index.ts +11 -0
  129. package/src/minecraft-loader/loader-registry.ts +72 -0
  130. package/src/shared/api/assets.ts +112 -0
  131. package/src/shared/api/auth.ts +283 -0
  132. package/src/shared/api/builds.ts +647 -0
  133. package/src/shared/api/config.ts +19 -0
  134. package/src/shared/api/download-stats.ts +103 -0
  135. package/src/shared/api/downloads.ts +36 -0
  136. package/src/shared/api/entity-authorship.ts +60 -0
  137. package/src/shared/api/events.ts +393 -0
  138. package/src/shared/api/friends.ts +140 -0
  139. package/src/shared/api/graphql.ts +87 -0
  140. package/src/shared/api/index.ts +23 -0
  141. package/src/shared/api/invites.ts +262 -0
  142. package/src/shared/api/library.ts +44 -0
  143. package/src/shared/api/maps.ts +385 -0
  144. package/src/shared/api/notify-websocket.ts +140 -0
  145. package/src/shared/api/posts.ts +357 -0
  146. package/src/shared/api/projectServers.ts +379 -0
  147. package/src/shared/api/serverMembers.ts +173 -0
  148. package/src/shared/api/users.ts +294 -0
  149. package/src/shared/composables/buildEditor/useBuildEditor.ts +66 -0
  150. package/src/shared/composables/buildManifest/buildManifest.ts +447 -0
  151. package/src/shared/composables/filesEditor/filesEditor.ts +346 -0
  152. package/src/shared/composables/index.ts +10 -0
  153. package/src/shared/composables/modsEditor/modsEditor.ts +1678 -0
  154. package/src/shared/composables/registrySlot/registry-slot-utils.ts +25 -0
  155. package/src/shared/composables/registrySlot/useRegistrySlotMissing.ts +35 -0
  156. package/src/shared/composables/resourcePacksEditor/resourcePacksEditor.ts +448 -0
  157. package/src/shared/composables/shaderPacksEditor/shaderPacksEditor.ts +395 -0
  158. package/src/shared/composables/useSkinRender.ts +70 -0
  159. package/src/shared/composables/useZlDeepLink.ts +178 -0
  160. package/src/shared/definitions/defineGraphCache.ts +216 -0
  161. package/src/shared/definitions/defineStore.ts +32 -0
  162. package/src/shared/definitions/index.ts +2 -0
  163. package/src/shared/minecraft-types/build-manifest.ts +611 -0
  164. package/src/shared/minecraft-types/index.ts +3 -0
  165. package/src/shared/minecraft-types/launcher-versions.ts +32 -0
  166. package/src/shared/minecraft-types/minecraft-launcher-types.ts +276 -0
  167. package/src/shared/mocks/index.ts +1 -0
  168. package/src/shared/mocks/navigation.ts +17 -0
  169. package/src/shared/mods/http.ts +45 -0
  170. package/src/shared/mods/index.ts +5 -0
  171. package/src/shared/mods/marketplace-editor-search.ts +266 -0
  172. package/src/shared/mods/marketplace-search-utils.ts +42 -0
  173. package/src/shared/mods/mod-marketplace-registry.ts +66 -0
  174. package/src/shared/mods/mod-marketplace-types.ts +28 -0
  175. package/src/shared/mods/providers/curseforge.ts +464 -0
  176. package/src/shared/mods/providers/index.ts +8 -0
  177. package/src/shared/mods/providers/modrinth.ts +402 -0
  178. package/src/shared/mods/resolve-mods-provider-loader-ids.ts +77 -0
  179. package/src/shared/mods/types.ts +76 -0
  180. package/src/shared/styles/index.css +713 -0
  181. package/src/shared/themes/index.ts +23 -0
  182. package/src/shared/themes/theme-tokens-black.json +126 -0
  183. package/src/shared/themes/theme-tokens-classic.json +126 -0
  184. package/src/shared/themes/theme-tokens-pink.json +126 -0
  185. package/src/shared/themes/theme-tokens.json +126 -0
  186. package/src/shared/themes/types.ts +85 -0
  187. package/src/shared/types/API_DOCUMENTATION.md +422 -0
  188. package/src/shared/types/account.ts +40 -0
  189. package/src/shared/types/build.ts +8 -0
  190. package/src/shared/types/entities.ts +181 -0
  191. package/src/shared/types/index.ts +6 -0
  192. package/src/shared/types/invite-payloads.ts +60 -0
  193. package/src/shared/types/navigation.ts +16 -0
  194. package/src/shared/types/running-build.ts +51 -0
  195. package/src/shared/types/serverMember.ts +17 -0
  196. package/src/shared/types/user.ts +55 -0
  197. package/src/shared/ui/base/Avatar.vue +262 -0
  198. package/src/shared/ui/base/Badge.vue +47 -0
  199. package/src/shared/ui/base/Button.vue +78 -0
  200. package/src/shared/ui/base/Divider.vue +42 -0
  201. package/src/shared/ui/base/Icon.vue +597 -0
  202. package/src/shared/ui/base/StatusIndicator.vue +44 -0
  203. package/src/shared/ui/base/index.ts +7 -0
  204. package/src/shared/ui/cards/InviteCard.vue +47 -0
  205. package/src/shared/ui/cards/index.ts +2 -0
  206. package/src/shared/ui/dialog/Dialog.vue +71 -0
  207. package/src/shared/ui/dialog/DialogContent.vue +31 -0
  208. package/src/shared/ui/dialog/DialogFooter.vue +14 -0
  209. package/src/shared/ui/dialog/DialogHeader.vue +41 -0
  210. package/src/shared/ui/dialog/index.ts +5 -0
  211. package/src/shared/ui/editors/AttachmentImagesEditor.vue +133 -0
  212. package/src/shared/ui/editors/ContentAttachmentsDisplay.vue +76 -0
  213. package/src/shared/ui/editors/MarkdownEditor.vue +956 -0
  214. package/src/shared/ui/editors/MarkdownRenderer.vue +299 -0
  215. package/src/shared/ui/editors/RichContentImageViewer.vue +85 -0
  216. package/src/shared/ui/editors/SocialPostMediaZone.vue +320 -0
  217. package/src/shared/ui/editors/index.ts +6 -0
  218. package/src/shared/ui/editors/markdown-editor-gallery.ts +234 -0
  219. package/src/shared/ui/editors/markdown-editor-image.ts +178 -0
  220. package/src/shared/ui/form/Checkbox.vue +38 -0
  221. package/src/shared/ui/form/FormField.vue +30 -0
  222. package/src/shared/ui/form/FormGrid.vue +38 -0
  223. package/src/shared/ui/form/ImageEditor.vue +598 -0
  224. package/src/shared/ui/form/Input.vue +72 -0
  225. package/src/shared/ui/form/Range.vue +65 -0
  226. package/src/shared/ui/form/Select.vue +76 -0
  227. package/src/shared/ui/form/Switch.vue +38 -0
  228. package/src/shared/ui/form/Textarea.vue +144 -0
  229. package/src/shared/ui/form/index.ts +9 -0
  230. package/src/shared/ui/index.ts +9 -0
  231. package/src/shared/ui/layout/BusyOverlay.vue +31 -0
  232. package/src/shared/ui/layout/Callout.vue +44 -0
  233. package/src/shared/ui/layout/Card.vue +38 -0
  234. package/src/shared/ui/layout/Container.vue +36 -0
  235. package/src/shared/ui/layout/EmptyState.vue +99 -0
  236. package/src/shared/ui/layout/EntityMediaRow.vue +54 -0
  237. package/src/shared/ui/layout/FilterResultsLayout.vue +22 -0
  238. package/src/shared/ui/layout/FloatingPanel.vue +37 -0
  239. package/src/shared/ui/layout/FullscreenDimmer.vue +11 -0
  240. package/src/shared/ui/layout/Grid.vue +40 -0
  241. package/src/shared/ui/layout/Inline.vue +59 -0
  242. package/src/shared/ui/layout/LoadingState.vue +39 -0
  243. package/src/shared/ui/layout/MediaBox.vue +47 -0
  244. package/src/shared/ui/layout/OverlayPanel.vue +28 -0
  245. package/src/shared/ui/layout/OverlayWaitPanel.vue +22 -0
  246. package/src/shared/ui/layout/PageSection.vue +43 -0
  247. package/src/shared/ui/layout/PageToolbar.vue +29 -0
  248. package/src/shared/ui/layout/Panel.vue +39 -0
  249. package/src/shared/ui/layout/ProgressBar.vue +49 -0
  250. package/src/shared/ui/layout/Section.vue +30 -0
  251. package/src/shared/ui/layout/SegmentedControl.vue +43 -0
  252. package/src/shared/ui/layout/SelectableCard.vue +46 -0
  253. package/src/shared/ui/layout/SelectableRow.vue +41 -0
  254. package/src/shared/ui/layout/Skeleton.vue +25 -0
  255. package/src/shared/ui/layout/SkeletonAvatar.vue +30 -0
  256. package/src/shared/ui/layout/SkeletonEntityCard.vue +20 -0
  257. package/src/shared/ui/layout/SkeletonFeedPost.vue +22 -0
  258. package/src/shared/ui/layout/SkeletonGrid.vue +18 -0
  259. package/src/shared/ui/layout/SkeletonListRow.vue +31 -0
  260. package/src/shared/ui/layout/SkeletonText.vue +25 -0
  261. package/src/shared/ui/layout/Stack.vue +42 -0
  262. package/src/shared/ui/layout/StateBlock.vue +44 -0
  263. package/src/shared/ui/layout/TwoPaneLayout.vue +35 -0
  264. package/src/shared/ui/layout/VirtualList.vue +160 -0
  265. package/src/shared/ui/layout/index.ts +35 -0
  266. package/src/shared/ui/layout/skeletonSurfaceStyles.ts +24 -0
  267. package/src/shared/ui/navigation/NavItem.vue +139 -0
  268. package/src/shared/ui/navigation/Tab.vue +61 -0
  269. package/src/shared/ui/navigation/Tabs.vue +37 -0
  270. package/src/shared/ui/navigation/index.ts +4 -0
  271. package/src/shared/ui/primitives/Action.vue +19 -0
  272. package/src/shared/ui/primitives/Block.vue +28 -0
  273. package/src/shared/ui/primitives/CanvasView.vue +19 -0
  274. package/src/shared/ui/primitives/Control.vue +24 -0
  275. package/src/shared/ui/primitives/ControlSelect.vue +19 -0
  276. package/src/shared/ui/primitives/ControlTextarea.vue +17 -0
  277. package/src/shared/ui/primitives/FieldLabel.vue +19 -0
  278. package/src/shared/ui/primitives/Form.vue +19 -0
  279. package/src/shared/ui/primitives/Heading.vue +29 -0
  280. package/src/shared/ui/primitives/Image.vue +17 -0
  281. package/src/shared/ui/primitives/LineBreak.vue +3 -0
  282. package/src/shared/ui/primitives/Link.vue +19 -0
  283. package/src/shared/ui/primitives/List.vue +28 -0
  284. package/src/shared/ui/primitives/ListItem.vue +19 -0
  285. package/src/shared/ui/primitives/OptionItem.vue +19 -0
  286. package/src/shared/ui/primitives/Text.vue +28 -0
  287. package/src/shared/ui/primitives/VideoView.vue +19 -0
  288. package/src/shared/ui/primitives/index.ts +19 -0
  289. package/src/shared/ui/primitives/resolveElement.ts +25 -0
  290. package/src/shared/ui/special/AngularAccent.vue +106 -0
  291. package/src/shared/ui/special/ExtensionRegistrySlotButton.vue +143 -0
  292. package/src/shared/ui/special/InfoRow.vue +39 -0
  293. package/src/shared/ui/special/LogViewer.vue +53 -0
  294. package/src/shared/ui/special/PageHeader.vue +23 -0
  295. package/src/shared/ui/special/RegistrySlotMissingCallout.vue +48 -0
  296. package/src/shared/ui/special/WelcomeCard.vue +32 -0
  297. package/src/shared/ui/special/index.ts +9 -0
  298. package/src/shared/utils/app-paths.ts +50 -0
  299. package/src/shared/utils/attachments.ts +16 -0
  300. package/src/shared/utils/autostart.ts +213 -0
  301. package/src/shared/utils/build-files.ts +439 -0
  302. package/src/shared/utils/build-manifest-init.ts +176 -0
  303. package/src/shared/utils/cloudinary.ts +67 -0
  304. package/src/shared/utils/cn.ts +7 -0
  305. package/src/shared/utils/download-stats-week.ts +165 -0
  306. package/src/shared/utils/entity-api-to-cache.ts +84 -0
  307. package/src/shared/utils/entity-build-from-api.ts +1 -0
  308. package/src/shared/utils/entity-display.ts +27 -0
  309. package/src/shared/utils/entity-map-from-api.ts +1 -0
  310. package/src/shared/utils/file-hash.ts +65 -0
  311. package/src/shared/utils/formatSize.ts +5 -0
  312. package/src/shared/utils/formatTime.ts +157 -0
  313. package/src/shared/utils/getAccountSkinRender.ts +32 -0
  314. package/src/shared/utils/index.ts +34 -0
  315. package/src/shared/utils/local-mods.ts +678 -0
  316. package/src/shared/utils/local-settings.ts +217 -0
  317. package/src/shared/utils/member-join-stats.ts +35 -0
  318. package/src/shared/utils/platform.ts +86 -0
  319. package/src/shared/utils/play-host-slug.ts +92 -0
  320. package/src/shared/utils/rich-content.ts +294 -0
  321. package/src/shared/utils/safeRequest.ts +23 -0
  322. package/src/shared/utils/semver.ts +81 -0
  323. package/src/shared/utils/serverPermissions.ts +155 -0
  324. package/src/shared/utils/skin-render-cache.ts +372 -0
  325. package/src/shared/utils/stripMarkdown.ts +45 -0
  326. package/src/shared/utils/transliterate.ts +74 -0
  327. package/src/shared/utils/updateAccountSkinRender.ts +64 -0
  328. package/src/shared/utils/updater.ts +218 -0
  329. package/src/shared/utils/uploadImage.ts +195 -0
  330. package/src/shared/utils/user-status.ts +9 -0
  331. package/src/tiptap/index.ts +7 -0
  332. package/tsconfig.json +13 -0
@@ -0,0 +1,165 @@
1
+ import type { DownloadDailyStatPoint } from '../api/download-stats';
2
+
3
+ export type WeekDownloadDay = {
4
+ date: string;
5
+ label: string;
6
+ count: number;
7
+ };
8
+
9
+ export type WeekDownloadStats = {
10
+ days: WeekDownloadDay[];
11
+ weekTotal: number;
12
+ previousWeekTotal: number;
13
+ weekDelta: number;
14
+ weekDeltaPercent: number | null;
15
+ };
16
+
17
+ function utcDateKey(date: Date): string {
18
+ return date.toISOString().slice(0, 10);
19
+ }
20
+
21
+ function addUtcDays(date: Date, days: number): Date {
22
+ const next = new Date(date);
23
+ next.setUTCDate(next.getUTCDate() + days);
24
+ return next;
25
+ }
26
+
27
+ function normalizeDateKey(raw: string): string {
28
+ if (/^\d{4}-\d{2}-\d{2}$/.test(raw)) return raw;
29
+ return utcDateKey(new Date(raw));
30
+ }
31
+
32
+ function aggregateDownloadPoints(
33
+ points: DownloadDailyStatPoint[],
34
+ ): Map<string, number> {
35
+ const byDate = new Map<string, number>();
36
+ for (const point of points) {
37
+ const dateKey = normalizeDateKey(point.date);
38
+ const count = Number(point.count) || 0;
39
+ byDate.set(dateKey, (byDate.get(dateKey) ?? 0) + count);
40
+ }
41
+ return byDate;
42
+ }
43
+
44
+ /** Последние 30 календарных дней UTC включая сегодня. */
45
+ export function getLastMonthUtcRange(): { from: string; to: string } {
46
+ const today = new Date();
47
+ const to = utcDateKey(today);
48
+ const from = utcDateKey(addUtcDays(today, -29));
49
+ return { from, to };
50
+ }
51
+
52
+ /**
53
+ * Диапазон для heatmap в стиле GitHub/GitLab: ~53 недели, начало с понедельника (UTC).
54
+ */
55
+ export function getHeatmapActivityUtcRange(): { from: string; to: string } {
56
+ const today = new Date();
57
+ const to = utcDateKey(today);
58
+ const weeks = 53;
59
+ let fromDate = addUtcDays(today, -(weeks * 7 - 1));
60
+
61
+ const weekday = fromDate.getUTCDay();
62
+ const mondayOffset = weekday === 0 ? -6 : 1 - weekday;
63
+ fromDate = addUtcDays(fromDate, mondayOffset);
64
+
65
+ return { from: utcDateKey(fromDate), to };
66
+ }
67
+
68
+ function formatDayLabel(dateKey: string): string {
69
+ const date = new Date(`${dateKey}T12:00:00.000Z`);
70
+ return date.toLocaleDateString('ru-RU', {
71
+ weekday: 'short',
72
+ day: 'numeric',
73
+ month: 'short',
74
+ timeZone: 'UTC',
75
+ });
76
+ }
77
+
78
+ /** Последние 7 календарных дней UTC включая сегодня. */
79
+ export function getLastWeekUtcRange(): { from: string; to: string } {
80
+ const today = new Date();
81
+ const to = utcDateKey(today);
82
+ const from = utcDateKey(addUtcDays(today, -6));
83
+ return { from, to };
84
+ }
85
+
86
+ /** Предыдущие 7 дней перед текущей неделей (для сравнения динамики). */
87
+ export function getPreviousWeekUtcRange(): { from: string; to: string } {
88
+ const today = new Date();
89
+ const to = utcDateKey(addUtcDays(today, -7));
90
+ const from = utcDateKey(addUtcDays(today, -13));
91
+ return { from, to };
92
+ }
93
+
94
+ function buildDaySeries(
95
+ from: string,
96
+ to: string,
97
+ points: DownloadDailyStatPoint[],
98
+ ): WeekDownloadDay[] {
99
+ const byDate = aggregateDownloadPoints(points);
100
+ const days: WeekDownloadDay[] = [];
101
+ let cursor = new Date(`${from}T00:00:00.000Z`);
102
+ const end = new Date(`${to}T00:00:00.000Z`);
103
+
104
+ while (cursor <= end) {
105
+ const date = utcDateKey(cursor);
106
+ days.push({
107
+ date,
108
+ label: formatDayLabel(date),
109
+ count: byDate.get(date) ?? 0,
110
+ });
111
+ cursor = addUtcDays(cursor, 1);
112
+ }
113
+
114
+ return days;
115
+ }
116
+
117
+ export function buildDownloadDaySeries(
118
+ from: string,
119
+ to: string,
120
+ points: DownloadDailyStatPoint[],
121
+ ): WeekDownloadDay[] {
122
+ return buildDaySeries(from, to, points);
123
+ }
124
+
125
+ export function sumDownloadPoints(points: DownloadDailyStatPoint[]): number {
126
+ let total = 0;
127
+ for (const count of aggregateDownloadPoints(points).values()) {
128
+ total += count;
129
+ }
130
+ return total;
131
+ }
132
+
133
+ export function buildWeekDownloadStats(
134
+ weekPoints: DownloadDailyStatPoint[],
135
+ previousWeekPoints: DownloadDailyStatPoint[],
136
+ range = getLastWeekUtcRange(),
137
+ ): WeekDownloadStats {
138
+ const days = buildDaySeries(range.from, range.to, weekPoints);
139
+ const weekTotal = sumDownloadPoints(weekPoints);
140
+ const previousWeekTotal = sumDownloadPoints(previousWeekPoints);
141
+ const weekDelta = weekTotal - previousWeekTotal;
142
+ const weekDeltaPercent =
143
+ previousWeekTotal > 0
144
+ ? Math.round((weekDelta / previousWeekTotal) * 100)
145
+ : weekTotal > 0
146
+ ? 100
147
+ : null;
148
+
149
+ return {
150
+ days,
151
+ weekTotal,
152
+ previousWeekTotal,
153
+ weekDelta,
154
+ weekDeltaPercent,
155
+ };
156
+ }
157
+
158
+ export function formatWeekDynamicsLabel(stats: WeekDownloadStats): string {
159
+ if (stats.weekDelta === 0) return 'Без изменений';
160
+ const sign = stats.weekDelta > 0 ? '+' : '';
161
+ if (stats.weekDeltaPercent == null) {
162
+ return `${sign}${stats.weekDelta}`;
163
+ }
164
+ return `${sign}${stats.weekDelta} (${sign}${stats.weekDeltaPercent}%)`;
165
+ }
@@ -0,0 +1,84 @@
1
+ import type { Build } from '../api/builds';
2
+ import type { Map } from '../api/maps';
3
+ import type { EntityBuild, EntityMap, EntityUser } from '../types/entities';
4
+
5
+ /** Фрагмент автора из GraphQL (id + username). */
6
+ export type EntityAuthorSnippet = Pick<EntityUser, 'id' | 'username'>;
7
+
8
+ export type BuildCachePayload = Omit<Partial<EntityBuild>, 'author' | 'authorPublic'> &
9
+ Pick<EntityBuild, 'id' | 'name'> & {
10
+ author?: EntityAuthorSnippet | null;
11
+ authorPublic?: EntityAuthorSnippet | null;
12
+ };
13
+
14
+ export type MapCachePayload = Omit<Partial<EntityMap>, 'author' | 'authorPublic'> &
15
+ Pick<EntityMap, 'id' | 'name'> & {
16
+ author?: EntityAuthorSnippet | null;
17
+ authorPublic?: EntityAuthorSnippet | null;
18
+ };
19
+
20
+ /**
21
+ * Payload для `buildsCache.merge`: только поля из ответа API, без fallback-значений.
22
+ */
23
+ export function buildApiToCache(b: Build): BuildCachePayload {
24
+ const payload: BuildCachePayload = {
25
+ id: b.id,
26
+ name: b.name,
27
+ description: b.description,
28
+ isPublic: b.isPublic,
29
+ };
30
+
31
+ if (b.image !== undefined) payload.image = b.image;
32
+ if (b.minecraftVersion !== undefined) payload.minecraftVersion = b.minecraftVersion;
33
+ if (b.loader !== undefined) payload.loader = b.loader;
34
+ if (b.downloads !== undefined) payload.downloads = b.downloads;
35
+ if (b.rating !== undefined) payload.rating = b.rating;
36
+ if (b.author) payload.author = { id: b.author.id, username: b.author.username };
37
+
38
+ return payload;
39
+ }
40
+
41
+ /**
42
+ * Payload для `mapsCache.merge`: только поля из ответа API, без fallback-значений.
43
+ */
44
+ export function mapApiToCache(m: Map): MapCachePayload {
45
+ const manifest = m.manifest as Record<string, unknown> | undefined;
46
+ const buildId =
47
+ (m.buildId || (manifest?.buildId as string) || '').trim() || undefined;
48
+ const buildName =
49
+ (m.buildName || (manifest?.buildName as string) || '').trim() || undefined;
50
+ const minecraftVersion =
51
+ (m.minecraftVersion || (manifest?.minecraftVersion as string) || '').trim() ||
52
+ undefined;
53
+ const mapType =
54
+ (m.mapType || (manifest?.mapType as Map['mapType']) || 'any') as Map['mapType'];
55
+
56
+ const payload: MapCachePayload = {
57
+ id: m.id,
58
+ name: m.name,
59
+ description: m.description,
60
+ minecraftVersion: minecraftVersion ?? m.minecraftVersion,
61
+ mapType,
62
+ version: m.version,
63
+ sha1: m.sha1,
64
+ size: m.size,
65
+ s3Url: m.s3Url,
66
+ isPublic: m.isPublic,
67
+ downloads: m.downloads,
68
+ };
69
+
70
+ if (m.image !== undefined) payload.image = m.image;
71
+ if (buildId) payload.buildId = buildId;
72
+ if (buildName) payload.buildName = buildName;
73
+ if (m.manifest !== undefined) payload.manifest = m.manifest;
74
+ if (m.createdAt !== undefined) payload.createdAt = m.createdAt;
75
+ if (m.author) payload.author = { id: m.author.id, username: m.author.username };
76
+
77
+ return payload;
78
+ }
79
+
80
+ /** @deprecated Используйте {@link buildApiToCache} */
81
+ export const entityBuildFromApiBuild = buildApiToCache;
82
+
83
+ /** @deprecated Используйте {@link mapApiToCache} */
84
+ export const entityMapFromApiMap = mapApiToCache;
@@ -0,0 +1 @@
1
+ export { buildApiToCache, entityBuildFromApiBuild } from './entity-api-to-cache';
@@ -0,0 +1,27 @@
1
+ import type {
2
+ EntityBuildBase,
3
+ EntityMapBase,
4
+ EntityUser,
5
+ } from '../types/entities';
6
+
7
+ /** Имя автора для UI: authorPublic → author. */
8
+ export function entityAuthorName(
9
+ entity: {
10
+ author?: EntityUser | null;
11
+ authorPublic?: EntityUser | null;
12
+ },
13
+ ): string | null {
14
+ return entity.authorPublic?.username ?? entity.author?.username ?? null;
15
+ }
16
+
17
+ export function entityBuildDownloadsForDisplay(
18
+ build: Pick<EntityBuildBase, 'downloads'>,
19
+ ): number {
20
+ return build.downloads ?? 0;
21
+ }
22
+
23
+ export function entityMapDownloadsForDisplay(
24
+ map: Pick<EntityMapBase, 'downloads'>,
25
+ ): number {
26
+ return map.downloads ?? 0;
27
+ }
@@ -0,0 +1 @@
1
+ export { mapApiToCache, entityMapFromApiMap } from './entity-api-to-cache';
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Утилиты для работы с хешами файлов
3
+ */
4
+
5
+ /**
6
+ * Вычисляет SHA1 хеш файла в NW.js окружении
7
+ */
8
+ export async function calculateFileSHA1(filePath: string): Promise<string> {
9
+ // Проверяем, что мы в NW.js окружении
10
+ if (typeof window === 'undefined' || !(window as any).nw) {
11
+ throw new Error('File operations are only available in NW.js environment');
12
+ }
13
+
14
+ const nw = (window as any).nw;
15
+ const fs = nw.require('fs');
16
+ const crypto = nw.require('crypto');
17
+
18
+ return new Promise((resolve, reject) => {
19
+ const hash = crypto.createHash('sha1');
20
+ const stream = fs.createReadStream(filePath);
21
+
22
+ stream.on('data', (data: Buffer) => {
23
+ hash.update(data);
24
+ });
25
+
26
+ stream.on('end', () => {
27
+ resolve(hash.digest('hex'));
28
+ });
29
+
30
+ stream.on('error', (error: Error) => {
31
+ reject(error);
32
+ });
33
+ });
34
+ }
35
+
36
+ /**
37
+ * Получает размер файла в байтах
38
+ */
39
+ export function getFileSize(filePath: string): number {
40
+ if (typeof window === 'undefined' || !(window as any).nw) {
41
+ throw new Error('File operations are only available in NW.js environment');
42
+ }
43
+
44
+ const nw = (window as any).nw;
45
+ const fs = nw.require('fs');
46
+
47
+ const stats = fs.statSync(filePath);
48
+ return stats.size;
49
+ }
50
+
51
+ /**
52
+ * Читает файл в буфер
53
+ */
54
+ export function readFileBuffer(filePath: string): Buffer {
55
+ if (typeof window === 'undefined' || !(window as any).nw) {
56
+ throw new Error('File operations are only available in NW.js environment');
57
+ }
58
+
59
+ const nw = (window as any).nw;
60
+ const fs = nw.require('fs');
61
+
62
+ return fs.readFileSync(filePath);
63
+ }
64
+
65
+
@@ -0,0 +1,5 @@
1
+ export const formatSize = (bytes: number) => {
2
+ if (bytes < 1024) return `${bytes} B`;
3
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
4
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
5
+ };
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Форматирует timestamp в формат времени HH:mm
3
+ * @param timestamp - ISO строка или timestamp в миллисекундах
4
+ * @returns Отформатированная строка (например, "14:30")
5
+ */
6
+ export function formatTime(timestamp: string | number): string {
7
+ const date = typeof timestamp === 'string' ? new Date(timestamp) : new Date(timestamp);
8
+
9
+ if (isNaN(date.getTime())) {
10
+ return '--:--';
11
+ }
12
+
13
+ const hours = date.getHours().toString().padStart(2, '0');
14
+ const minutes = date.getMinutes().toString().padStart(2, '0');
15
+
16
+ return `${hours}:${minutes}`;
17
+ }
18
+
19
+ /**
20
+ * Форматирует timestamp (ISO строка или число) в относительное текстовое представление
21
+ * @param timestamp - ISO строка или timestamp в миллисекундах
22
+ * @returns Отформатированная строка (например, "2 часа назад", "5 дней назад")
23
+ */
24
+ export function formatRelativeTime(timestamp: string | number): string {
25
+ const now = Date.now();
26
+ const date = typeof timestamp === 'string' ? new Date(timestamp).getTime() : timestamp;
27
+
28
+ if (isNaN(date)) {
29
+ return 'Неизвестно';
30
+ }
31
+
32
+ const diff = now - date;
33
+ const seconds = Math.floor(diff / 1000);
34
+ const minutes = Math.floor(seconds / 60);
35
+ const hours = Math.floor(minutes / 60);
36
+ const days = Math.floor(hours / 24);
37
+ const weeks = Math.floor(days / 7);
38
+ const months = Math.floor(days / 30);
39
+ const years = Math.floor(days / 365);
40
+
41
+ if (seconds < 60) {
42
+ return 'только что';
43
+ } else if (minutes < 60) {
44
+ return `${minutes} ${getMinutesDeclension(minutes)} назад`;
45
+ } else if (hours < 24) {
46
+ return `${hours} ${getHoursDeclension(hours)} назад`;
47
+ } else if (days < 7) {
48
+ return `${days} ${getDaysDeclension(days)} назад`;
49
+ } else if (weeks < 4) {
50
+ return `${weeks} ${getWeeksDeclension(weeks)} назад`;
51
+ } else if (months < 12) {
52
+ return `${months} ${getMonthsDeclension(months)} назад`;
53
+ } else {
54
+ return `${years} ${getYearsDeclension(years)} назад`;
55
+ }
56
+ }
57
+
58
+ function getMinutesDeclension(count: number): string {
59
+ if (count % 10 === 1 && count % 100 !== 11) return 'минуту';
60
+ if ([2, 3, 4].includes(count % 10) && ![12, 13, 14].includes(count % 100)) return 'минуты';
61
+ return 'минут';
62
+ }
63
+
64
+ function getHoursDeclension(count: number): string {
65
+ if (count % 10 === 1 && count % 100 !== 11) return 'час';
66
+ if ([2, 3, 4].includes(count % 10) && ![12, 13, 14].includes(count % 100)) return 'часа';
67
+ return 'часов';
68
+ }
69
+
70
+ function getDaysDeclension(count: number): string {
71
+ if (count % 10 === 1 && count % 100 !== 11) return 'день';
72
+ if ([2, 3, 4].includes(count % 10) && ![12, 13, 14].includes(count % 100)) return 'дня';
73
+ return 'дней';
74
+ }
75
+
76
+ function getWeeksDeclension(count: number): string {
77
+ if (count % 10 === 1 && count % 100 !== 11) return 'неделю';
78
+ if ([2, 3, 4].includes(count % 10) && ![12, 13, 14].includes(count % 100)) return 'недели';
79
+ return 'недель';
80
+ }
81
+
82
+ function getMonthsDeclension(count: number): string {
83
+ if (count % 10 === 1 && count % 100 !== 11) return 'месяц';
84
+ if ([2, 3, 4].includes(count % 10) && ![12, 13, 14].includes(count % 100)) return 'месяца';
85
+ return 'месяцев';
86
+ }
87
+
88
+ function getYearsDeclension(count: number): string {
89
+ if (count % 10 === 1 && count % 100 !== 11) return 'год';
90
+ if ([2, 3, 4].includes(count % 10) && ![12, 13, 14].includes(count % 100)) return 'года';
91
+ return 'лет';
92
+ }
93
+
94
+ /**
95
+ * Форматирует дату в человекопонятный формат
96
+ * @param timestamp - ISO строка или timestamp в миллисекундах
97
+ * @returns Отформатированная строка (например, "Сегодня", "Вчера", "15 января", "15 января 2024")
98
+ */
99
+ export function formatDate(timestamp: string | number): string {
100
+ const date = typeof timestamp === 'string' ? new Date(timestamp) : new Date(timestamp);
101
+
102
+ if (isNaN(date.getTime())) {
103
+ return '';
104
+ }
105
+
106
+ const now = new Date();
107
+ const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
108
+ const messageDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
109
+ const yesterday = new Date(today);
110
+ yesterday.setDate(yesterday.getDate() - 1);
111
+
112
+ // Сравниваем только даты (без времени)
113
+ const diffTime = messageDate.getTime() - today.getTime();
114
+ const diffDays = Math.round(diffTime / (1000 * 60 * 60 * 24));
115
+
116
+ if (diffDays === 0) {
117
+ return 'Сегодня';
118
+ } else if (diffDays === -1) {
119
+ return 'Вчера';
120
+ } else if (diffDays === 1) {
121
+ return 'Завтра';
122
+ } else {
123
+ // Форматируем дату: "15 января" или "15 января 2024" (если не текущий год)
124
+ const day = date.getDate();
125
+ const monthNames = [
126
+ 'января', 'февраля', 'марта', 'апреля', 'мая', 'июня',
127
+ 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря'
128
+ ];
129
+ const month = monthNames[date.getMonth()];
130
+ const year = date.getFullYear();
131
+ const currentYear = now.getFullYear();
132
+
133
+ if (year === currentYear) {
134
+ return `${day} ${month}`;
135
+ } else {
136
+ return `${day} ${month} ${year}`;
137
+ }
138
+ }
139
+ }
140
+
141
+ /**
142
+ * Получает дату в формате YYYY-MM-DD для сравнения
143
+ */
144
+ export function getDateKey(timestamp: string | number): string {
145
+ const date = typeof timestamp === 'string' ? new Date(timestamp) : new Date(timestamp);
146
+
147
+ if (isNaN(date.getTime())) {
148
+ return '';
149
+ }
150
+
151
+ const year = date.getFullYear();
152
+ const month = String(date.getMonth() + 1).padStart(2, '0');
153
+ const day = String(date.getDate()).padStart(2, '0');
154
+
155
+ return `${year}-${month}-${day}`;
156
+ }
157
+
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Утилита для получения рендера скина аккаунта
3
+ */
4
+
5
+ import { getSkinRender } from './skin-render-cache';
6
+ import type { MinecraftAccount } from '../types/account';
7
+
8
+ /**
9
+ * Получить рендер скина для аккаунта
10
+ * Возвращает file:// URL для использования в img src
11
+ */
12
+ export async function getAccountSkinRender(account: MinecraftAccount): Promise<string | null> {
13
+ if (!account.avatar) {
14
+ return null;
15
+ }
16
+
17
+ // Проверяем, что мы в NW.js окружении
18
+ if (typeof window === 'undefined' || !(window as any).nw) {
19
+ return account.avatar;
20
+ }
21
+
22
+ try {
23
+ // Используем SHA1, если он есть, для более быстрого кеширования
24
+ const render = await getSkinRender(account.avatar, account.skinSha1 || undefined);
25
+ return render;
26
+ } catch (error) {
27
+ console.error('[Account Skin Render] Failed to get skin render:', error);
28
+ // В случае ошибки возвращаем оригинальный URL скина
29
+ return account.avatar;
30
+ }
31
+ }
32
+
@@ -0,0 +1,34 @@
1
+ export * from './attachments';
2
+ export * from './app-paths';
3
+ export * from './autostart';
4
+ export * from './build-files';
5
+ export * from './build-manifest-init';
6
+ export * from './cloudinary';
7
+ export * from './cn';
8
+ export * from './download-stats-week';
9
+ export * from './member-join-stats';
10
+ export * from './entity-api-to-cache';
11
+ export * from './entity-build-from-api';
12
+ export * from './entity-display';
13
+ export * from './entity-map-from-api';
14
+ export * from './file-hash';
15
+ export * from './formatSize';
16
+ export * from './formatTime';
17
+ export * from './getAccountSkinRender';
18
+
19
+ export * from './local-mods';
20
+ export * from './local-settings';
21
+ export * from './platform';
22
+ export * from './rich-content';
23
+ export * from './safeRequest';
24
+ export * from './semver';
25
+ export * from './serverPermissions';
26
+ export * from './skin-render-cache';
27
+ export * from './stripMarkdown';
28
+ export * from './transliterate';
29
+ export * from './updateAccountSkinRender';
30
+ export * from './updater';
31
+ export * from './uploadImage';
32
+ export * from './user-status';
33
+ export * from './play-host-slug';
34
+