@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.
- package/README.md +122 -0
- package/REGISTRIES.md +189 -0
- package/env.d.ts +11 -0
- package/host-shims.d.ts +30 -0
- package/package.json +88 -0
- package/src/extension-marketplace/api-types.ts +141 -0
- package/src/extension-marketplace/client.ts +296 -0
- package/src/extension-marketplace/index.ts +22 -0
- package/src/extension-marketplace/schemas.ts +178 -0
- package/src/extensions/ExtensionRoutePage.vue +17 -0
- package/src/extensions/context.ts +37 -0
- package/src/extensions/disabled-folder.ts +21 -0
- package/src/extensions/extension-expose-map.ts +5 -0
- package/src/extensions/extension-expose.ts +48 -0
- package/src/extensions/graph.ts +67 -0
- package/src/extensions/index.ts +251 -0
- package/src/extensions/invite-handler/types.ts +20 -0
- package/src/extensions/launcher-entities/create-launcher-entity.ts +25 -0
- package/src/extensions/launcher-entities/keys.ts +46 -0
- package/src/extensions/launcher-entities/launcher-entity-components.ts +177 -0
- package/src/extensions/launcher-entities/props-map.ts +69 -0
- package/src/extensions/launcher-entities/registry.ts +32 -0
- package/src/extensions/launcher-models/apis/accounts-contracts.ts +102 -0
- package/src/extensions/launcher-models/apis/launcher-model-apis.ts +553 -0
- package/src/extensions/launcher-models/keys.ts +23 -0
- package/src/extensions/launcher-models/public.ts +9 -0
- package/src/extensions/launcher-models/registry-core.ts +34 -0
- package/src/extensions/manifest-types.ts +22 -0
- package/src/extensions/manifest.ts +46 -0
- package/src/extensions/marketplace-open-key.ts +26 -0
- package/src/extensions/plugin-types.ts +44 -0
- package/src/extensions/plugin.ts +62 -0
- package/src/extensions/registries/bootstrap.ts +11 -0
- package/src/extensions/registries/builtins/account-provider.ts +6 -0
- package/src/extensions/registries/builtins/app-topbar-left-widgets.ts +6 -0
- package/src/extensions/registries/builtins/app-topbar-right-widgets.ts +6 -0
- package/src/extensions/registries/builtins/app-topbar-status-widgets.ts +6 -0
- package/src/extensions/registries/builtins/build-card-actions.ts +6 -0
- package/src/extensions/registries/builtins/build-card-after-meta.ts +6 -0
- package/src/extensions/registries/builtins/build-card-before-media.ts +6 -0
- package/src/extensions/registries/builtins/build-card-before-meta.ts +6 -0
- package/src/extensions/registries/builtins/build-card-footer-actions.ts +6 -0
- package/src/extensions/registries/builtins/build-detail-after-content.ts +6 -0
- package/src/extensions/registries/builtins/build-detail-before-content.ts +6 -0
- package/src/extensions/registries/builtins/build-detail-before-hero.ts +6 -0
- package/src/extensions/registries/builtins/build-detail-header-actions.ts +6 -0
- package/src/extensions/registries/builtins/build-detail-mod-row-actions.ts +6 -0
- package/src/extensions/registries/builtins/build-detail-resourcepack-row-actions.ts +6 -0
- package/src/extensions/registries/builtins/build-detail-right-column-bottom.ts +6 -0
- package/src/extensions/registries/builtins/build-detail-right-column-top.ts +6 -0
- package/src/extensions/registries/builtins/dialog-footer-actions.ts +6 -0
- package/src/extensions/registries/builtins/feed-after-content.ts +6 -0
- package/src/extensions/registries/builtins/feed-before-content.ts +6 -0
- package/src/extensions/registries/builtins/file-editor.ts +19 -0
- package/src/extensions/registries/builtins/friends-after-list.ts +6 -0
- package/src/extensions/registries/builtins/friends-before-list.ts +6 -0
- package/src/extensions/registries/builtins/index.ts +141 -0
- package/src/extensions/registries/builtins/invite-handler.ts +7 -0
- package/src/extensions/registries/builtins/library-after-content.ts +6 -0
- package/src/extensions/registries/builtins/library-before-content.ts +6 -0
- package/src/extensions/registries/builtins/loader.ts +8 -0
- package/src/extensions/registries/builtins/map-card-actions.ts +6 -0
- package/src/extensions/registries/builtins/map-card-after-meta.ts +6 -0
- package/src/extensions/registries/builtins/map-card-before-meta.ts +6 -0
- package/src/extensions/registries/builtins/map-card-footer-actions.ts +6 -0
- package/src/extensions/registries/builtins/map-detail-after-content.ts +6 -0
- package/src/extensions/registries/builtins/map-detail-before-content.ts +6 -0
- package/src/extensions/registries/builtins/map-detail-header-actions.ts +6 -0
- package/src/extensions/registries/builtins/markdown-editor-tiptap-extensions.ts +7 -0
- package/src/extensions/registries/builtins/markdown-editor-toolbar-actions.ts +6 -0
- package/src/extensions/registries/builtins/markdown-renderer-after-content.ts +6 -0
- package/src/extensions/registries/builtins/markdown-renderer-before-content.ts +6 -0
- package/src/extensions/registries/builtins/mod-details-footer-actions.ts +6 -0
- package/src/extensions/registries/builtins/mod-manage-actions.ts +6 -0
- package/src/extensions/registries/builtins/mod-provider.ts +5 -0
- package/src/extensions/registries/builtins/nav.ts +7 -0
- package/src/extensions/registries/builtins/page.ts +13 -0
- package/src/extensions/registries/builtins/projects-after-content.ts +6 -0
- package/src/extensions/registries/builtins/projects-before-content.ts +6 -0
- package/src/extensions/registries/builtins/resourcepack-manage-actions.ts +7 -0
- package/src/extensions/registries/builtins/server-card-actions.ts +6 -0
- package/src/extensions/registries/builtins/server-card-after-meta.ts +6 -0
- package/src/extensions/registries/builtins/server-card-before-meta.ts +6 -0
- package/src/extensions/registries/builtins/server-card-footer-actions.ts +6 -0
- package/src/extensions/registries/builtins/server-detail-after-content.ts +6 -0
- package/src/extensions/registries/builtins/server-detail-before-content.ts +6 -0
- package/src/extensions/registries/builtins/server-detail-header-actions.ts +6 -0
- package/src/extensions/registries/builtins/settings-after-sections.ts +6 -0
- package/src/extensions/registries/builtins/settings-before-sections.ts +6 -0
- package/src/extensions/registries/builtins/settings-section-widgets.ts +6 -0
- package/src/extensions/registries/builtins/shaderpack-manage-actions.ts +7 -0
- package/src/extensions/registries/builtins/shell.ts +5 -0
- package/src/extensions/registries/builtins/sidebar-after-content.ts +6 -0
- package/src/extensions/registries/builtins/sidebar-before-content.ts +6 -0
- package/src/extensions/registries/builtins/sidebar-footer-widgets.ts +6 -0
- package/src/extensions/registries/builtins/sidebar-header-widgets.ts +6 -0
- package/src/extensions/registries/builtins/sidebar.ts +11 -0
- package/src/extensions/registries/builtins/theme.ts +5 -0
- package/src/extensions/registries/builtins/user-card-after-meta.ts +6 -0
- package/src/extensions/registries/builtins/user-card-before-meta.ts +6 -0
- package/src/extensions/registries/builtins/user-menu-actions.ts +6 -0
- package/src/extensions/registries/builtins/user-menu-after-actions.ts +6 -0
- package/src/extensions/registries/builtins/user-menu-before-actions.ts +6 -0
- package/src/extensions/registries/builtins/user-strip.ts +5 -0
- package/src/extensions/registries/clear-extension-ui-registries.ts +15 -0
- package/src/extensions/registries/define-extension-registry.ts +58 -0
- package/src/extensions/registries/extension-host-api.ts +41 -0
- package/src/extensions/registries/extension-registry-api.ts +103 -0
- package/src/extensions/registries/extension-registry-payload-map.ts +9 -0
- package/src/extensions/registries/extension-scope.ts +41 -0
- package/src/extensions/registries/get-registry.ts +23 -0
- package/src/extensions/registries/index.ts +58 -0
- package/src/extensions/registries/manifest-rynt.ts +193 -0
- package/src/extensions/registries/registry-slot.ts +40 -0
- package/src/extensions/registries/registry-value-map.ts +89 -0
- package/src/extensions/registries/store.ts +206 -0
- package/src/extensions/resolve-extensions.ts +245 -0
- package/src/extensions/router-bridge.ts +103 -0
- package/src/extensions/session.ts +6 -0
- package/src/extensions/slug.ts +23 -0
- package/src/extensions/version.ts +147 -0
- package/src/host/extensions-composables.ts +33 -0
- package/src/host/extensions-init.ts +194 -0
- package/src/host/index.ts +11 -0
- package/src/host/launcher-models/index.ts +4 -0
- package/src/index.ts +229 -0
- package/src/minecraft-loader/base-loader.ts +102 -0
- package/src/minecraft-loader/index.ts +11 -0
- package/src/minecraft-loader/loader-registry.ts +72 -0
- package/src/shared/api/assets.ts +112 -0
- package/src/shared/api/auth.ts +283 -0
- package/src/shared/api/builds.ts +647 -0
- package/src/shared/api/config.ts +19 -0
- package/src/shared/api/download-stats.ts +103 -0
- package/src/shared/api/downloads.ts +36 -0
- package/src/shared/api/entity-authorship.ts +60 -0
- package/src/shared/api/events.ts +393 -0
- package/src/shared/api/friends.ts +140 -0
- package/src/shared/api/graphql.ts +87 -0
- package/src/shared/api/index.ts +23 -0
- package/src/shared/api/invites.ts +262 -0
- package/src/shared/api/library.ts +44 -0
- package/src/shared/api/maps.ts +385 -0
- package/src/shared/api/notify-websocket.ts +140 -0
- package/src/shared/api/posts.ts +357 -0
- package/src/shared/api/projectServers.ts +379 -0
- package/src/shared/api/serverMembers.ts +173 -0
- package/src/shared/api/users.ts +294 -0
- package/src/shared/composables/buildEditor/useBuildEditor.ts +66 -0
- package/src/shared/composables/buildManifest/buildManifest.ts +447 -0
- package/src/shared/composables/filesEditor/filesEditor.ts +346 -0
- package/src/shared/composables/index.ts +10 -0
- package/src/shared/composables/modsEditor/modsEditor.ts +1678 -0
- package/src/shared/composables/registrySlot/registry-slot-utils.ts +25 -0
- package/src/shared/composables/registrySlot/useRegistrySlotMissing.ts +35 -0
- package/src/shared/composables/resourcePacksEditor/resourcePacksEditor.ts +448 -0
- package/src/shared/composables/shaderPacksEditor/shaderPacksEditor.ts +395 -0
- package/src/shared/composables/useSkinRender.ts +70 -0
- package/src/shared/composables/useZlDeepLink.ts +178 -0
- package/src/shared/definitions/defineGraphCache.ts +216 -0
- package/src/shared/definitions/defineStore.ts +32 -0
- package/src/shared/definitions/index.ts +2 -0
- package/src/shared/minecraft-types/build-manifest.ts +611 -0
- package/src/shared/minecraft-types/index.ts +3 -0
- package/src/shared/minecraft-types/launcher-versions.ts +32 -0
- package/src/shared/minecraft-types/minecraft-launcher-types.ts +276 -0
- package/src/shared/mocks/index.ts +1 -0
- package/src/shared/mocks/navigation.ts +17 -0
- package/src/shared/mods/http.ts +45 -0
- package/src/shared/mods/index.ts +5 -0
- package/src/shared/mods/marketplace-editor-search.ts +266 -0
- package/src/shared/mods/marketplace-search-utils.ts +42 -0
- package/src/shared/mods/mod-marketplace-registry.ts +66 -0
- package/src/shared/mods/mod-marketplace-types.ts +28 -0
- package/src/shared/mods/providers/curseforge.ts +464 -0
- package/src/shared/mods/providers/index.ts +8 -0
- package/src/shared/mods/providers/modrinth.ts +402 -0
- package/src/shared/mods/resolve-mods-provider-loader-ids.ts +77 -0
- package/src/shared/mods/types.ts +76 -0
- package/src/shared/styles/index.css +713 -0
- package/src/shared/themes/index.ts +23 -0
- package/src/shared/themes/theme-tokens-black.json +126 -0
- package/src/shared/themes/theme-tokens-classic.json +126 -0
- package/src/shared/themes/theme-tokens-pink.json +126 -0
- package/src/shared/themes/theme-tokens.json +126 -0
- package/src/shared/themes/types.ts +85 -0
- package/src/shared/types/API_DOCUMENTATION.md +422 -0
- package/src/shared/types/account.ts +40 -0
- package/src/shared/types/build.ts +8 -0
- package/src/shared/types/entities.ts +181 -0
- package/src/shared/types/index.ts +6 -0
- package/src/shared/types/invite-payloads.ts +60 -0
- package/src/shared/types/navigation.ts +16 -0
- package/src/shared/types/running-build.ts +51 -0
- package/src/shared/types/serverMember.ts +17 -0
- package/src/shared/types/user.ts +55 -0
- package/src/shared/ui/base/Avatar.vue +262 -0
- package/src/shared/ui/base/Badge.vue +47 -0
- package/src/shared/ui/base/Button.vue +78 -0
- package/src/shared/ui/base/Divider.vue +42 -0
- package/src/shared/ui/base/Icon.vue +597 -0
- package/src/shared/ui/base/StatusIndicator.vue +44 -0
- package/src/shared/ui/base/index.ts +7 -0
- package/src/shared/ui/cards/InviteCard.vue +47 -0
- package/src/shared/ui/cards/index.ts +2 -0
- package/src/shared/ui/dialog/Dialog.vue +71 -0
- package/src/shared/ui/dialog/DialogContent.vue +31 -0
- package/src/shared/ui/dialog/DialogFooter.vue +14 -0
- package/src/shared/ui/dialog/DialogHeader.vue +41 -0
- package/src/shared/ui/dialog/index.ts +5 -0
- package/src/shared/ui/editors/AttachmentImagesEditor.vue +133 -0
- package/src/shared/ui/editors/ContentAttachmentsDisplay.vue +76 -0
- package/src/shared/ui/editors/MarkdownEditor.vue +956 -0
- package/src/shared/ui/editors/MarkdownRenderer.vue +299 -0
- package/src/shared/ui/editors/RichContentImageViewer.vue +85 -0
- package/src/shared/ui/editors/SocialPostMediaZone.vue +320 -0
- package/src/shared/ui/editors/index.ts +6 -0
- package/src/shared/ui/editors/markdown-editor-gallery.ts +234 -0
- package/src/shared/ui/editors/markdown-editor-image.ts +178 -0
- package/src/shared/ui/form/Checkbox.vue +38 -0
- package/src/shared/ui/form/FormField.vue +30 -0
- package/src/shared/ui/form/FormGrid.vue +38 -0
- package/src/shared/ui/form/ImageEditor.vue +598 -0
- package/src/shared/ui/form/Input.vue +72 -0
- package/src/shared/ui/form/Range.vue +65 -0
- package/src/shared/ui/form/Select.vue +76 -0
- package/src/shared/ui/form/Switch.vue +38 -0
- package/src/shared/ui/form/Textarea.vue +144 -0
- package/src/shared/ui/form/index.ts +9 -0
- package/src/shared/ui/index.ts +9 -0
- package/src/shared/ui/layout/BusyOverlay.vue +31 -0
- package/src/shared/ui/layout/Callout.vue +44 -0
- package/src/shared/ui/layout/Card.vue +38 -0
- package/src/shared/ui/layout/Container.vue +36 -0
- package/src/shared/ui/layout/EmptyState.vue +99 -0
- package/src/shared/ui/layout/EntityMediaRow.vue +54 -0
- package/src/shared/ui/layout/FilterResultsLayout.vue +22 -0
- package/src/shared/ui/layout/FloatingPanel.vue +37 -0
- package/src/shared/ui/layout/FullscreenDimmer.vue +11 -0
- package/src/shared/ui/layout/Grid.vue +40 -0
- package/src/shared/ui/layout/Inline.vue +59 -0
- package/src/shared/ui/layout/LoadingState.vue +39 -0
- package/src/shared/ui/layout/MediaBox.vue +47 -0
- package/src/shared/ui/layout/OverlayPanel.vue +28 -0
- package/src/shared/ui/layout/OverlayWaitPanel.vue +22 -0
- package/src/shared/ui/layout/PageSection.vue +43 -0
- package/src/shared/ui/layout/PageToolbar.vue +29 -0
- package/src/shared/ui/layout/Panel.vue +39 -0
- package/src/shared/ui/layout/ProgressBar.vue +49 -0
- package/src/shared/ui/layout/Section.vue +30 -0
- package/src/shared/ui/layout/SegmentedControl.vue +43 -0
- package/src/shared/ui/layout/SelectableCard.vue +46 -0
- package/src/shared/ui/layout/SelectableRow.vue +41 -0
- package/src/shared/ui/layout/Skeleton.vue +25 -0
- package/src/shared/ui/layout/SkeletonAvatar.vue +30 -0
- package/src/shared/ui/layout/SkeletonEntityCard.vue +20 -0
- package/src/shared/ui/layout/SkeletonFeedPost.vue +22 -0
- package/src/shared/ui/layout/SkeletonGrid.vue +18 -0
- package/src/shared/ui/layout/SkeletonListRow.vue +31 -0
- package/src/shared/ui/layout/SkeletonText.vue +25 -0
- package/src/shared/ui/layout/Stack.vue +42 -0
- package/src/shared/ui/layout/StateBlock.vue +44 -0
- package/src/shared/ui/layout/TwoPaneLayout.vue +35 -0
- package/src/shared/ui/layout/VirtualList.vue +160 -0
- package/src/shared/ui/layout/index.ts +35 -0
- package/src/shared/ui/layout/skeletonSurfaceStyles.ts +24 -0
- package/src/shared/ui/navigation/NavItem.vue +139 -0
- package/src/shared/ui/navigation/Tab.vue +61 -0
- package/src/shared/ui/navigation/Tabs.vue +37 -0
- package/src/shared/ui/navigation/index.ts +4 -0
- package/src/shared/ui/primitives/Action.vue +19 -0
- package/src/shared/ui/primitives/Block.vue +28 -0
- package/src/shared/ui/primitives/CanvasView.vue +19 -0
- package/src/shared/ui/primitives/Control.vue +24 -0
- package/src/shared/ui/primitives/ControlSelect.vue +19 -0
- package/src/shared/ui/primitives/ControlTextarea.vue +17 -0
- package/src/shared/ui/primitives/FieldLabel.vue +19 -0
- package/src/shared/ui/primitives/Form.vue +19 -0
- package/src/shared/ui/primitives/Heading.vue +29 -0
- package/src/shared/ui/primitives/Image.vue +17 -0
- package/src/shared/ui/primitives/LineBreak.vue +3 -0
- package/src/shared/ui/primitives/Link.vue +19 -0
- package/src/shared/ui/primitives/List.vue +28 -0
- package/src/shared/ui/primitives/ListItem.vue +19 -0
- package/src/shared/ui/primitives/OptionItem.vue +19 -0
- package/src/shared/ui/primitives/Text.vue +28 -0
- package/src/shared/ui/primitives/VideoView.vue +19 -0
- package/src/shared/ui/primitives/index.ts +19 -0
- package/src/shared/ui/primitives/resolveElement.ts +25 -0
- package/src/shared/ui/special/AngularAccent.vue +106 -0
- package/src/shared/ui/special/ExtensionRegistrySlotButton.vue +143 -0
- package/src/shared/ui/special/InfoRow.vue +39 -0
- package/src/shared/ui/special/LogViewer.vue +53 -0
- package/src/shared/ui/special/PageHeader.vue +23 -0
- package/src/shared/ui/special/RegistrySlotMissingCallout.vue +48 -0
- package/src/shared/ui/special/WelcomeCard.vue +32 -0
- package/src/shared/ui/special/index.ts +9 -0
- package/src/shared/utils/app-paths.ts +50 -0
- package/src/shared/utils/attachments.ts +16 -0
- package/src/shared/utils/autostart.ts +213 -0
- package/src/shared/utils/build-files.ts +439 -0
- package/src/shared/utils/build-manifest-init.ts +176 -0
- package/src/shared/utils/cloudinary.ts +67 -0
- package/src/shared/utils/cn.ts +7 -0
- package/src/shared/utils/download-stats-week.ts +165 -0
- package/src/shared/utils/entity-api-to-cache.ts +84 -0
- package/src/shared/utils/entity-build-from-api.ts +1 -0
- package/src/shared/utils/entity-display.ts +27 -0
- package/src/shared/utils/entity-map-from-api.ts +1 -0
- package/src/shared/utils/file-hash.ts +65 -0
- package/src/shared/utils/formatSize.ts +5 -0
- package/src/shared/utils/formatTime.ts +157 -0
- package/src/shared/utils/getAccountSkinRender.ts +32 -0
- package/src/shared/utils/index.ts +34 -0
- package/src/shared/utils/local-mods.ts +678 -0
- package/src/shared/utils/local-settings.ts +217 -0
- package/src/shared/utils/member-join-stats.ts +35 -0
- package/src/shared/utils/platform.ts +86 -0
- package/src/shared/utils/play-host-slug.ts +92 -0
- package/src/shared/utils/rich-content.ts +294 -0
- package/src/shared/utils/safeRequest.ts +23 -0
- package/src/shared/utils/semver.ts +81 -0
- package/src/shared/utils/serverPermissions.ts +155 -0
- package/src/shared/utils/skin-render-cache.ts +372 -0
- package/src/shared/utils/stripMarkdown.ts +45 -0
- package/src/shared/utils/transliterate.ts +74 -0
- package/src/shared/utils/updateAccountSkinRender.ts +64 -0
- package/src/shared/utils/updater.ts +218 -0
- package/src/shared/utils/uploadImage.ts +195 -0
- package/src/shared/utils/user-status.ts +9 -0
- package/src/tiptap/index.ts +7 -0
- package/tsconfig.json +13 -0
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
import type { BuildVersionManifest } from '../minecraft-types/build-manifest';
|
|
2
|
+
import { getBuildDirectory } from './local-mods';
|
|
3
|
+
|
|
4
|
+
// Проверка на наличие Node.js окружения (NW.js)
|
|
5
|
+
const isNodeEnv = typeof window !== 'undefined' && (window as any).nw;
|
|
6
|
+
|
|
7
|
+
// Динамическая загрузка Node.js модулей
|
|
8
|
+
let fs: any;
|
|
9
|
+
let path: any;
|
|
10
|
+
|
|
11
|
+
if (isNodeEnv) {
|
|
12
|
+
try {
|
|
13
|
+
const nw = (window as any).nw;
|
|
14
|
+
fs = nw.require('fs');
|
|
15
|
+
path = nw.require('path');
|
|
16
|
+
} catch (error) {
|
|
17
|
+
console.error('Не удалось загрузить Node.js модули:', error);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Категория файла
|
|
23
|
+
*/
|
|
24
|
+
export type FileCategory =
|
|
25
|
+
| 'included'
|
|
26
|
+
| 'ignored'
|
|
27
|
+
| 'selectable'
|
|
28
|
+
| 'unavailable';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Информация о файле в дереве файлов
|
|
32
|
+
*/
|
|
33
|
+
export interface BuildFileInfo {
|
|
34
|
+
/**
|
|
35
|
+
* Путь относительно директории сборки
|
|
36
|
+
*/
|
|
37
|
+
path: string;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Полный путь к файлу
|
|
41
|
+
*/
|
|
42
|
+
fullPath: string;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Имя файла или директории
|
|
46
|
+
*/
|
|
47
|
+
name: string;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Это директория?
|
|
51
|
+
*/
|
|
52
|
+
isDirectory: boolean;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Размер файла в байтах (только для файлов)
|
|
56
|
+
*/
|
|
57
|
+
size?: number;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Категория файла
|
|
61
|
+
*/
|
|
62
|
+
category: FileCategory;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Выбран ли файл для включения в сборку
|
|
66
|
+
*/
|
|
67
|
+
selected: boolean;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Пропускать проверку хеша при загрузке (для конфигов, которые игрок может редактировать)
|
|
71
|
+
*/
|
|
72
|
+
skipHash?: boolean;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Дочерние элементы (для директорий)
|
|
76
|
+
*/
|
|
77
|
+
children?: BuildFileInfo[];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Проверить, должен ли путь быть недоступен для выбора
|
|
82
|
+
*/
|
|
83
|
+
function isUnavailablePath(filePath: string, fileName: string): boolean {
|
|
84
|
+
if (!path) return false;
|
|
85
|
+
|
|
86
|
+
// Директории и файлы, которые нельзя выбрать
|
|
87
|
+
const unavailableItems = [
|
|
88
|
+
'saves',
|
|
89
|
+
'.fabric',
|
|
90
|
+
'logs',
|
|
91
|
+
'usercache.json',
|
|
92
|
+
'downloads',
|
|
93
|
+
'realms_persistence.json',
|
|
94
|
+
];
|
|
95
|
+
|
|
96
|
+
// Проверяем имя файла/директории
|
|
97
|
+
if (unavailableItems.includes(fileName.toLowerCase())) {
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Проверяем путь (например, "saves/world1" тоже должен быть недоступен)
|
|
102
|
+
const normalizedPath = filePath.replace(/\\/g, '/').toLowerCase();
|
|
103
|
+
for (const unavailable of unavailableItems) {
|
|
104
|
+
if (
|
|
105
|
+
normalizedPath.startsWith(unavailable + '/') ||
|
|
106
|
+
normalizedPath === unavailable
|
|
107
|
+
) {
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Проверить, является ли путь игнорируемым по умолчанию
|
|
117
|
+
*/
|
|
118
|
+
function isIgnoredPath(filePath: string, fileName: string): boolean {
|
|
119
|
+
if (!path) return false;
|
|
120
|
+
|
|
121
|
+
// Файлы с расширением .disabled
|
|
122
|
+
if (fileName.endsWith('.disabled')) {
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Директории, начинающиеся с "." (кроме .fabric, который уже в unavailable)
|
|
127
|
+
if (fileName.startsWith('.') && fileName !== '.fabric') {
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Конкретные файлы и директории для игнорирования
|
|
132
|
+
const ignoredItems = ['options.txt', 'defaultconfigs'];
|
|
133
|
+
|
|
134
|
+
// Проверяем имя файла/директории
|
|
135
|
+
if (ignoredItems.includes(fileName.toLowerCase())) {
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Проверяем путь (например, "saves/world1" тоже должен игнорироваться)
|
|
140
|
+
const normalizedPath = filePath.replace(/\\/g, '/').toLowerCase();
|
|
141
|
+
for (const ignored of ignoredItems) {
|
|
142
|
+
if (
|
|
143
|
+
normalizedPath.startsWith(ignored + '/') ||
|
|
144
|
+
normalizedPath === ignored
|
|
145
|
+
) {
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Проверить, является ли файл уже включенным в сборку
|
|
155
|
+
*/
|
|
156
|
+
function isIncludedFile(
|
|
157
|
+
filePath: string,
|
|
158
|
+
fileName: string,
|
|
159
|
+
manifest: BuildVersionManifest | null,
|
|
160
|
+
): boolean {
|
|
161
|
+
if (!manifest || !path) return false;
|
|
162
|
+
|
|
163
|
+
// version-manifest.json всегда включен
|
|
164
|
+
if (fileName === 'version-manifest.json') {
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// <minecraftVersion>.jar всегда включен
|
|
169
|
+
const minecraftVersion = manifest._meta?.manifest?.minecraftVersion;
|
|
170
|
+
if (minecraftVersion && fileName === `${minecraftVersion}.jar`) {
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Проверяем моды
|
|
175
|
+
if (manifest.mods) {
|
|
176
|
+
for (const mod of manifest.mods) {
|
|
177
|
+
for (const file of mod.files || []) {
|
|
178
|
+
const modPath = file.path || `mods/${file.filename}`;
|
|
179
|
+
if (modPath === filePath || path.basename(modPath) === fileName) {
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Проверяем ресурспаки
|
|
187
|
+
if (manifest.resourcePacks) {
|
|
188
|
+
for (const rp of manifest.resourcePacks) {
|
|
189
|
+
for (const file of rp.files || []) {
|
|
190
|
+
const rpPath = file.path || `resourcepacks/${file.filename}`;
|
|
191
|
+
if (rpPath === filePath || path.basename(rpPath) === fileName) {
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Проверяем шейдеры
|
|
199
|
+
if (manifest.shaderPacks) {
|
|
200
|
+
for (const sp of manifest.shaderPacks) {
|
|
201
|
+
for (const file of sp.files || []) {
|
|
202
|
+
const spPath = file.path || `shaderpacks/${file.filename}`;
|
|
203
|
+
if (spPath === filePath || path.basename(spPath) === fileName) {
|
|
204
|
+
return true;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// versionAssets не проверяем - они формируются на беке из выбранных файлов
|
|
211
|
+
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Рекурсивно сканировать директорию и построить дерево файлов
|
|
217
|
+
*/
|
|
218
|
+
function scanDirectory(
|
|
219
|
+
dirPath: string,
|
|
220
|
+
relativePath: string,
|
|
221
|
+
manifest: BuildVersionManifest | null,
|
|
222
|
+
selectedFiles: Map<string, { skipHash?: boolean }>,
|
|
223
|
+
): BuildFileInfo[] {
|
|
224
|
+
if (!isNodeEnv || !fs || !path) return [];
|
|
225
|
+
|
|
226
|
+
const files: BuildFileInfo[] = [];
|
|
227
|
+
|
|
228
|
+
try {
|
|
229
|
+
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
230
|
+
|
|
231
|
+
for (const entry of entries) {
|
|
232
|
+
const fileName = entry.name;
|
|
233
|
+
const fullPath = path.join(dirPath, fileName);
|
|
234
|
+
const relativeFilePath = relativePath
|
|
235
|
+
? `${relativePath}/${fileName}`
|
|
236
|
+
: fileName;
|
|
237
|
+
|
|
238
|
+
// Пропускаем version-manifest.json в корне (он уже включен)
|
|
239
|
+
if (relativePath === '' && fileName === 'version-manifest.json') {
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const isDir = entry.isDirectory();
|
|
244
|
+
let size: number | undefined;
|
|
245
|
+
let category: FileCategory;
|
|
246
|
+
let children: BuildFileInfo[] | undefined;
|
|
247
|
+
|
|
248
|
+
if (isDir) {
|
|
249
|
+
// Рекурсивно сканируем поддиректорию
|
|
250
|
+
children = scanDirectory(
|
|
251
|
+
fullPath,
|
|
252
|
+
relativeFilePath,
|
|
253
|
+
manifest,
|
|
254
|
+
selectedFiles,
|
|
255
|
+
);
|
|
256
|
+
} else {
|
|
257
|
+
// Получаем размер файла
|
|
258
|
+
try {
|
|
259
|
+
const stats = fs.statSync(fullPath);
|
|
260
|
+
size = stats.size;
|
|
261
|
+
} catch (error) {
|
|
262
|
+
console.error(
|
|
263
|
+
`Ошибка при получении размера файла ${fullPath}:`,
|
|
264
|
+
error,
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Определяем категорию
|
|
270
|
+
if (isIncludedFile(relativeFilePath, fileName, manifest)) {
|
|
271
|
+
category = 'included';
|
|
272
|
+
} else if (isUnavailablePath(relativeFilePath, fileName)) {
|
|
273
|
+
category = 'unavailable';
|
|
274
|
+
} else if (isIgnoredPath(relativeFilePath, fileName)) {
|
|
275
|
+
category = 'ignored';
|
|
276
|
+
} else {
|
|
277
|
+
category = 'selectable';
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Проверяем, выбран ли файл
|
|
281
|
+
const selectedFileInfo = selectedFiles.get(relativeFilePath);
|
|
282
|
+
const selected = !!selectedFileInfo;
|
|
283
|
+
const skipHash = selectedFileInfo?.skipHash || false;
|
|
284
|
+
|
|
285
|
+
const fileInfo: BuildFileInfo = {
|
|
286
|
+
path: relativeFilePath,
|
|
287
|
+
fullPath,
|
|
288
|
+
name: fileName,
|
|
289
|
+
isDirectory: isDir,
|
|
290
|
+
size,
|
|
291
|
+
category,
|
|
292
|
+
selected,
|
|
293
|
+
skipHash: selected ? skipHash : undefined,
|
|
294
|
+
children: isDir ? children : undefined,
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
files.push(fileInfo);
|
|
298
|
+
}
|
|
299
|
+
} catch (error) {
|
|
300
|
+
console.error(`Ошибка при сканировании директории ${dirPath}:`, error);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Сортируем: сначала директории, потом файлы, по алфавиту
|
|
304
|
+
files.sort((a, b) => {
|
|
305
|
+
if (a.isDirectory !== b.isDirectory) {
|
|
306
|
+
return a.isDirectory ? -1 : 1;
|
|
307
|
+
}
|
|
308
|
+
return a.name.localeCompare(b.name);
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
return files;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Сканировать файлы сборки и построить дерево
|
|
316
|
+
*/
|
|
317
|
+
export function scanBuildFiles(
|
|
318
|
+
buildId: string,
|
|
319
|
+
manifest: BuildVersionManifest | null,
|
|
320
|
+
explicitBuildDir?: string,
|
|
321
|
+
): BuildFileInfo[] {
|
|
322
|
+
if (!isNodeEnv || !fs || !path) {
|
|
323
|
+
throw new Error('Node.js окружение недоступно');
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Если сборка еще не сохранена (ID = '_new'), возвращаем пустой массив
|
|
327
|
+
// Файлы появятся только после первого сохранения
|
|
328
|
+
if (!buildId || buildId === '_new') {
|
|
329
|
+
return [];
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const buildDir = explicitBuildDir || getBuildDirectory(buildId);
|
|
333
|
+
if (!buildDir) {
|
|
334
|
+
throw new Error('Не удалось получить путь к директории сборки');
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const dirExists = fs.existsSync(buildDir);
|
|
338
|
+
if (!dirExists) {
|
|
339
|
+
// Если директория не существует, возвращаем пустой массив вместо ошибки
|
|
340
|
+
// Это может произойти, если сборка еще не была сохранена
|
|
341
|
+
return [];
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
try {
|
|
345
|
+
// Проверяем, что это директория
|
|
346
|
+
const stats = fs.statSync(buildDir);
|
|
347
|
+
if (!stats.isDirectory()) {
|
|
348
|
+
throw new Error(`Путь не является директорией: ${buildDir}`);
|
|
349
|
+
}
|
|
350
|
+
} catch (error) {
|
|
351
|
+
throw new Error(
|
|
352
|
+
`Ошибка при доступе к директории ${buildDir}: ${error instanceof Error ? error.message : 'Неизвестная ошибка'}`,
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// Преобразуем selectedFiles из массива объектов в Map для быстрого доступа
|
|
357
|
+
const selectedFiles = new Map<string, { skipHash?: boolean }>();
|
|
358
|
+
if (manifest?.selectedFiles) {
|
|
359
|
+
for (const file of manifest.selectedFiles) {
|
|
360
|
+
if (typeof file === 'string') {
|
|
361
|
+
// Поддержка старого формата (массив строк) для обратной совместимости
|
|
362
|
+
selectedFiles.set(file, {});
|
|
363
|
+
} else {
|
|
364
|
+
selectedFiles.set(file.path, { skipHash: file.skipHash });
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// Сканируем директорию
|
|
370
|
+
return scanDirectory(buildDir, '', manifest, selectedFiles);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Вычислить общий размер выбранных файлов
|
|
375
|
+
*/
|
|
376
|
+
export function calculateSelectedFilesSize(files: BuildFileInfo[]): number {
|
|
377
|
+
let totalSize = 0;
|
|
378
|
+
|
|
379
|
+
function traverse(fileList: BuildFileInfo[]) {
|
|
380
|
+
for (const file of fileList) {
|
|
381
|
+
if (file.selected && !file.isDirectory && file.size) {
|
|
382
|
+
totalSize += file.size;
|
|
383
|
+
}
|
|
384
|
+
if (file.children) {
|
|
385
|
+
traverse(file.children);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
traverse(files);
|
|
391
|
+
return totalSize;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Подсчитать количество выбранных файлов
|
|
396
|
+
*/
|
|
397
|
+
export function countSelectedFiles(files: BuildFileInfo[]): number {
|
|
398
|
+
let count = 0;
|
|
399
|
+
|
|
400
|
+
function traverse(fileList: BuildFileInfo[]) {
|
|
401
|
+
for (const file of fileList) {
|
|
402
|
+
if (file.selected && !file.isDirectory) {
|
|
403
|
+
count++;
|
|
404
|
+
}
|
|
405
|
+
if (file.children) {
|
|
406
|
+
traverse(file.children);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
traverse(files);
|
|
412
|
+
return count;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Получить все выбранные файлы из дерева файлов
|
|
417
|
+
*/
|
|
418
|
+
export function getSelectedPaths(
|
|
419
|
+
files: BuildFileInfo[],
|
|
420
|
+
): Array<{ path: string; skipHash?: boolean }> {
|
|
421
|
+
const result: Array<{ path: string; skipHash?: boolean }> = [];
|
|
422
|
+
|
|
423
|
+
function traverse(fileList: BuildFileInfo[]) {
|
|
424
|
+
for (const file of fileList) {
|
|
425
|
+
if (file.selected && !file.isDirectory) {
|
|
426
|
+
result.push({
|
|
427
|
+
path: file.path,
|
|
428
|
+
skipHash: file.skipHash || undefined,
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
if (file.children) {
|
|
432
|
+
traverse(file.children);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
traverse(files);
|
|
438
|
+
return result;
|
|
439
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import type { BuildVersionManifest } from '../minecraft-types/build-manifest';
|
|
2
|
+
import { cloneDeep } from 'lodash-es';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Эталонный минимальный манифест сборки
|
|
6
|
+
*/
|
|
7
|
+
export function getDefaultBuildManifest(
|
|
8
|
+
uuid: string,
|
|
9
|
+
name: string = 'Новая сборка',
|
|
10
|
+
): BuildVersionManifest {
|
|
11
|
+
const now = new Date().toISOString();
|
|
12
|
+
return {
|
|
13
|
+
id: uuid,
|
|
14
|
+
type: 'release',
|
|
15
|
+
arguments: {
|
|
16
|
+
game: [],
|
|
17
|
+
jvm: [],
|
|
18
|
+
},
|
|
19
|
+
libraries: [],
|
|
20
|
+
_meta: {
|
|
21
|
+
uuid: '',
|
|
22
|
+
name: name,
|
|
23
|
+
version: '0.0.0',
|
|
24
|
+
releaseTime: now,
|
|
25
|
+
time: now,
|
|
26
|
+
settings: {
|
|
27
|
+
javaPath: '',
|
|
28
|
+
jvmArgs: '',
|
|
29
|
+
maxRam: 2048,
|
|
30
|
+
},
|
|
31
|
+
manifest: {
|
|
32
|
+
minecraftVersion: '',
|
|
33
|
+
loader: 'vanilla',
|
|
34
|
+
loaderVersion: '',
|
|
35
|
+
},
|
|
36
|
+
description: '',
|
|
37
|
+
image: '',
|
|
38
|
+
stats: {
|
|
39
|
+
lastPlayed: '',
|
|
40
|
+
playTime: 0,
|
|
41
|
+
},
|
|
42
|
+
author: {
|
|
43
|
+
id: '',
|
|
44
|
+
username: '',
|
|
45
|
+
name: '',
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
versionAssets: [],
|
|
49
|
+
mods: [],
|
|
50
|
+
resourcePacks: [],
|
|
51
|
+
shaderPacks: [],
|
|
52
|
+
selectedFiles: [],
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Инициализировать манифест сборки, мержа эталонный манифест с существующими данными
|
|
58
|
+
* @param existingManifest Существующий манифест (если есть)
|
|
59
|
+
* @param uuid UUID сборки
|
|
60
|
+
* @param name Название сборки
|
|
61
|
+
* @returns Инициализированный манифест
|
|
62
|
+
*/
|
|
63
|
+
export function initializeBuildManifest(
|
|
64
|
+
existingManifest: BuildVersionManifest | null,
|
|
65
|
+
uuid?: string,
|
|
66
|
+
name?: string,
|
|
67
|
+
): BuildVersionManifest {
|
|
68
|
+
// Создаем эталонный манифест
|
|
69
|
+
const defaultManifest = getDefaultBuildManifest(
|
|
70
|
+
uuid || '',
|
|
71
|
+
name || existingManifest?._meta?.name || 'Новая сборка',
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
if (!existingManifest) {
|
|
75
|
+
// Если манифеста нет, возвращаем эталонный
|
|
76
|
+
return cloneDeep(defaultManifest);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Клонируем существующий манифест, чтобы не изменять оригинал
|
|
80
|
+
const manifest = cloneDeep(existingManifest);
|
|
81
|
+
|
|
82
|
+
// Мержим _meta, сохраняя существующие данные
|
|
83
|
+
if (!manifest._meta) {
|
|
84
|
+
manifest._meta = cloneDeep(defaultManifest._meta);
|
|
85
|
+
} else {
|
|
86
|
+
// Мержим поля _meta, сохраняя существующие значения
|
|
87
|
+
const defaultMeta = defaultManifest._meta!;
|
|
88
|
+
|
|
89
|
+
// Убеждаемся, что обязательные поля существуют
|
|
90
|
+
if (!manifest._meta.uuid) {
|
|
91
|
+
manifest._meta.uuid = defaultMeta.uuid;
|
|
92
|
+
}
|
|
93
|
+
if (!manifest._meta.name) {
|
|
94
|
+
manifest._meta.name = defaultMeta.name;
|
|
95
|
+
}
|
|
96
|
+
if (!manifest._meta.version) {
|
|
97
|
+
manifest._meta.version = defaultMeta.version;
|
|
98
|
+
}
|
|
99
|
+
if (!manifest._meta.releaseTime) {
|
|
100
|
+
manifest._meta.releaseTime = defaultMeta.releaseTime;
|
|
101
|
+
}
|
|
102
|
+
if (!manifest._meta.time) {
|
|
103
|
+
manifest._meta.time = defaultMeta.time;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Мержим settings
|
|
107
|
+
if (!manifest._meta.settings) {
|
|
108
|
+
manifest._meta.settings = cloneDeep(defaultMeta.settings);
|
|
109
|
+
} else {
|
|
110
|
+
// Убеждаемся, что все поля settings существуют
|
|
111
|
+
if (manifest._meta.settings.javaPath === undefined) {
|
|
112
|
+
manifest._meta.settings.javaPath = defaultMeta.settings!.javaPath;
|
|
113
|
+
}
|
|
114
|
+
if (manifest._meta.settings.jvmArgs === undefined) {
|
|
115
|
+
manifest._meta.settings.jvmArgs = defaultMeta.settings!.jvmArgs;
|
|
116
|
+
}
|
|
117
|
+
if (manifest._meta.settings.maxRam === undefined) {
|
|
118
|
+
manifest._meta.settings.maxRam = defaultMeta.settings!.maxRam;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Мержим manifest (информация о версии Minecraft и загрузчике)
|
|
123
|
+
if (!manifest._meta.manifest) {
|
|
124
|
+
manifest._meta.manifest = cloneDeep(defaultMeta.manifest);
|
|
125
|
+
} else {
|
|
126
|
+
// Убеждаемся, что все поля manifest существуют
|
|
127
|
+
// НЕ перезаписываем, если поле уже заполнено пользователем (не пустое и не undefined)
|
|
128
|
+
if (manifest._meta.manifest.minecraftVersion === undefined) {
|
|
129
|
+
manifest._meta.manifest.minecraftVersion =
|
|
130
|
+
defaultMeta.manifest!.minecraftVersion;
|
|
131
|
+
}
|
|
132
|
+
// Если поле пустое (''), НЕ перезаписываем его дефолтным значением - это может быть намеренно
|
|
133
|
+
// Но если undefined, используем дефолтное значение
|
|
134
|
+
if (manifest._meta.manifest.loader === undefined) {
|
|
135
|
+
manifest._meta.manifest.loader = defaultMeta.manifest!.loader;
|
|
136
|
+
}
|
|
137
|
+
if (manifest._meta.manifest.loaderVersion === undefined) {
|
|
138
|
+
manifest._meta.manifest.loaderVersion =
|
|
139
|
+
defaultMeta.manifest!.loaderVersion;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Убеждаемся, что основные поля манифеста существуют
|
|
145
|
+
if (!manifest.id) {
|
|
146
|
+
manifest.id = defaultManifest.id;
|
|
147
|
+
}
|
|
148
|
+
if (!manifest.type) {
|
|
149
|
+
manifest.type = defaultManifest.type;
|
|
150
|
+
}
|
|
151
|
+
if (!manifest.arguments) {
|
|
152
|
+
manifest.arguments = cloneDeep(defaultManifest.arguments);
|
|
153
|
+
}
|
|
154
|
+
if (!manifest.libraries) {
|
|
155
|
+
manifest.libraries = cloneDeep(defaultManifest.libraries);
|
|
156
|
+
}
|
|
157
|
+
// Сохраняем существующие mods и resourcePacks, если они есть
|
|
158
|
+
if (!manifest.mods) {
|
|
159
|
+
manifest.mods = [];
|
|
160
|
+
}
|
|
161
|
+
if (!manifest.resourcePacks) {
|
|
162
|
+
manifest.resourcePacks = [];
|
|
163
|
+
}
|
|
164
|
+
if (!manifest.shaderPacks) {
|
|
165
|
+
manifest.shaderPacks = [];
|
|
166
|
+
}
|
|
167
|
+
if (!manifest.versionAssets) {
|
|
168
|
+
manifest.versionAssets = [];
|
|
169
|
+
}
|
|
170
|
+
// Инициализируем selectedFiles, если его нет
|
|
171
|
+
if (!manifest.selectedFiles) {
|
|
172
|
+
manifest.selectedFiles = [];
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return manifest;
|
|
176
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export interface CloudinaryTransformOptions {
|
|
2
|
+
width?: number;
|
|
3
|
+
height?: number;
|
|
4
|
+
crop?: 'limit' | 'fill' | 'fit' | 'scale' | 'thumb' | 'crop';
|
|
5
|
+
quality?: number | 'auto';
|
|
6
|
+
format?: 'auto' | 'webp' | 'jpg' | 'png';
|
|
7
|
+
gravity?: 'auto' | 'face' | 'center';
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Добавляет трансформации Cloudinary к URL изображения
|
|
12
|
+
* @param url Оригинальный URL от Cloudinary
|
|
13
|
+
* @param options Параметры трансформации
|
|
14
|
+
* @returns URL с трансформациями
|
|
15
|
+
*/
|
|
16
|
+
export function transformCloudinaryUrl(
|
|
17
|
+
url: string | undefined | null,
|
|
18
|
+
options: CloudinaryTransformOptions
|
|
19
|
+
): string {
|
|
20
|
+
if (!url || !url.includes('cloudinary.com')) {
|
|
21
|
+
return url || ''; // Возвращаем оригинальный URL если это не Cloudinary
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const transformations: string[] = [];
|
|
25
|
+
|
|
26
|
+
if (options.width) {
|
|
27
|
+
transformations.push(`w_${options.width}`);
|
|
28
|
+
}
|
|
29
|
+
if (options.height) {
|
|
30
|
+
transformations.push(`h_${options.height}`);
|
|
31
|
+
}
|
|
32
|
+
if (options.crop) {
|
|
33
|
+
transformations.push(`c_${options.crop}`);
|
|
34
|
+
} else if (options.width || options.height) {
|
|
35
|
+
// По умолчанию используем limit если указаны размеры
|
|
36
|
+
transformations.push('c_limit');
|
|
37
|
+
}
|
|
38
|
+
if (options.quality) {
|
|
39
|
+
transformations.push(`q_${options.quality}`);
|
|
40
|
+
} else {
|
|
41
|
+
// Автоматическое качество по умолчанию
|
|
42
|
+
transformations.push('q_auto');
|
|
43
|
+
}
|
|
44
|
+
if (options.format) {
|
|
45
|
+
transformations.push(`f_${options.format}`);
|
|
46
|
+
} else {
|
|
47
|
+
// Автоматический формат по умолчанию
|
|
48
|
+
transformations.push('f_auto');
|
|
49
|
+
}
|
|
50
|
+
if (options.gravity) {
|
|
51
|
+
transformations.push(`g_${options.gravity}`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (transformations.length === 0) {
|
|
55
|
+
return url;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const transformString = transformations.join(',');
|
|
59
|
+
|
|
60
|
+
// Вставляем трансформации между /upload/ и версией/путем
|
|
61
|
+
// Формат: https://res.cloudinary.com/{cloud}/image/upload/{transformations}/{version}/{path}
|
|
62
|
+
return url.replace(
|
|
63
|
+
/\/upload\/(v\d+\/)?/,
|
|
64
|
+
`/upload/${transformString}/$1`
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|