@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,245 @@
1
+ import semver from 'semver';
2
+
3
+ import type { RyntExtensionManifestParsed } from './manifest-types';
4
+ import { topoSortExtensions } from './graph';
5
+ import {
6
+ applyValidatedRyntContributesToManifest,
7
+ flattenExtendsRegistries,
8
+ getRyntContributesFromManifest,
9
+ KNOWN_CORE_REGISTRY_IDS,
10
+ } from './registries/manifest-rynt';
11
+ import { checkExtensionApi } from './version';
12
+
13
+ export interface RyntDiscoveredExtensionLike {
14
+ manifest: RyntExtensionManifestParsed;
15
+ }
16
+
17
+ export interface ExtensionManifestIndex {
18
+ /** registryId → manifest.id владельца */
19
+ declaredBy: Map<string, string>;
20
+ /** `${registryId}\0${key}` → manifest.id[] */
21
+ slotClaims: Map<string, string[]>;
22
+ }
23
+
24
+ function slotClaimKey(registryId: string, key: string): string {
25
+ return `${registryId}\0${key}`;
26
+ }
27
+
28
+ export function buildExtensionManifestIndex(
29
+ byId: Map<string, RyntExtensionManifestParsed>,
30
+ ): { ok: true; index: ExtensionManifestIndex } | { ok: false; error: string } {
31
+ const declaredBy = new Map<string, string>();
32
+ const slotClaims = new Map<string, string[]>();
33
+
34
+ for (const [extId, manifest] of byId) {
35
+ const contributes = getRyntContributesFromManifest(manifest);
36
+
37
+ for (const decl of contributes?.declaresRegistries ?? []) {
38
+ const prev = declaredBy.get(decl.id);
39
+ if (prev !== undefined && prev !== extId) {
40
+ return {
41
+ ok: false,
42
+ error: `Registry "${decl.id}" declared by both "${prev}" and "${extId}"`,
43
+ };
44
+ }
45
+ declaredBy.set(decl.id, extId);
46
+ }
47
+
48
+ for (const { registryId, key } of flattenExtendsRegistries(contributes)) {
49
+ const sk = slotClaimKey(registryId, key);
50
+ const list = slotClaims.get(sk) ?? [];
51
+ list.push(extId);
52
+ slotClaims.set(sk, list);
53
+ }
54
+ }
55
+
56
+ return { ok: true, index: { declaredBy, slotClaims } };
57
+ }
58
+
59
+ function mergeImpliedDependencies(
60
+ byId: Map<string, RyntExtensionManifestParsed>,
61
+ index: ExtensionManifestIndex,
62
+ ): Map<string, Record<string, string>> {
63
+ const graph = new Map<string, Record<string, string>>();
64
+
65
+ for (const [id, manifest] of byId) {
66
+ graph.set(id, { ...(manifest.extensionDependencies ?? {}) });
67
+ }
68
+
69
+ for (const [extId, manifest] of byId) {
70
+ const contributes = getRyntContributesFromManifest(manifest);
71
+ for (const { registryId } of flattenExtendsRegistries(contributes)) {
72
+ if (KNOWN_CORE_REGISTRY_IDS.has(registryId)) {
73
+ continue;
74
+ }
75
+ const owner = index.declaredBy.get(registryId);
76
+ if (!owner) {
77
+ continue;
78
+ }
79
+ if (owner === extId) {
80
+ continue;
81
+ }
82
+ const deps = graph.get(extId) ?? {};
83
+ if (!(owner in deps)) {
84
+ deps[owner] = '*';
85
+ graph.set(extId, deps);
86
+ if (process.env.NODE_ENV !== 'production') {
87
+ console.info(
88
+ `[rynt/extensions] Implied dependency: «${extId}» → «${owner}» (registry ${registryId})`,
89
+ );
90
+ }
91
+ }
92
+ }
93
+ }
94
+
95
+ return graph;
96
+ }
97
+
98
+ export function validateExtensionDependencyVersions(
99
+ byId: Map<string, RyntExtensionManifestParsed>,
100
+ mergedDeps: Map<string, Record<string, string>>,
101
+ ): Record<string, string> {
102
+ const errors: Record<string, string> = {};
103
+
104
+ for (const [extId, deps] of mergedDeps) {
105
+ for (const [depId, range] of Object.entries(deps)) {
106
+ const dep = byId.get(depId);
107
+ if (!dep) {
108
+ continue;
109
+ }
110
+ const ver = semver.coerce(dep.version)?.version ?? dep.version;
111
+ if (!semver.validRange(range)) {
112
+ errors[extId] =
113
+ errors[extId] ??
114
+ `extensionDependencies["${depId}"]: invalid range "${range}"`;
115
+ continue;
116
+ }
117
+ if (!semver.satisfies(ver, range)) {
118
+ let msg = `extensionDependencies["${depId}"]: installed v${dep.version} does not satisfy ${range}`;
119
+ if (/^\^0\.0\.\d+$/u.test(range.trim())) {
120
+ msg +=
121
+ ' (для 0.0.x диапазон ^0.0.N не включает 0.0.(N+1); укажите >=0.0.N или ^0.0.M с нужным M)';
122
+ }
123
+ errors[extId] = errors[extId] ? `${errors[extId]}; ${msg}` : msg;
124
+ }
125
+ }
126
+ }
127
+
128
+ return errors;
129
+ }
130
+
131
+ export interface ResolveExtensionsResult {
132
+ order: string[];
133
+ errors: Record<string, string>;
134
+ index: ExtensionManifestIndex;
135
+ }
136
+
137
+ export type ResolveExtensionsLoadResult =
138
+ | ({ ok: true } & ResolveExtensionsResult)
139
+ | { ok: false; error: string };
140
+
141
+ export function resolveExtensionsForLoad(
142
+ extensions: RyntDiscoveredExtensionLike[],
143
+ options?: {
144
+ launcherVersion?: string;
145
+ strictExtensionApi?: boolean;
146
+ },
147
+ ): ResolveExtensionsLoadResult {
148
+ const errors: Record<string, string> = {};
149
+ const byId = new Map<string, RyntExtensionManifestParsed>();
150
+
151
+ for (const item of extensions) {
152
+ const id = item.manifest.id;
153
+ if (byId.has(id)) {
154
+ errors[id] = 'Duplicate extension id';
155
+ continue;
156
+ }
157
+ const manifest = { ...item.manifest };
158
+ const contribErr = applyContributesOrSkip(manifest);
159
+ if (contribErr) {
160
+ errors[id] = contribErr;
161
+ continue;
162
+ }
163
+ byId.set(id, manifest);
164
+ }
165
+
166
+ const indexResult = buildExtensionManifestIndex(byId);
167
+ if (!indexResult.ok) {
168
+ return { ok: false, error: indexResult.error };
169
+ }
170
+ const index = indexResult.index;
171
+
172
+ for (const [extId, manifest] of byId) {
173
+ const contributes = getRyntContributesFromManifest(manifest);
174
+ for (const { registryId } of flattenExtendsRegistries(contributes)) {
175
+ if (KNOWN_CORE_REGISTRY_IDS.has(registryId)) {
176
+ continue;
177
+ }
178
+ if (!index.declaredBy.has(registryId)) {
179
+ const msg = `extendsRegistries: registry "${registryId}" is not declared by any enabled extension`;
180
+ errors[extId] = errors[extId] ? `${errors[extId]}; ${msg}` : msg;
181
+ }
182
+ }
183
+ }
184
+
185
+ for (const [extId, manifest] of byId) {
186
+ const api = checkExtensionApi(manifest, {
187
+ strict: options?.strictExtensionApi,
188
+ });
189
+ if (!api.ok && api.message) {
190
+ errors[extId] = errors[extId]
191
+ ? `${errors[extId]}; ${api.message}`
192
+ : api.message;
193
+ if (api.blocking) {
194
+ byId.delete(extId);
195
+ }
196
+ }
197
+ }
198
+
199
+ if (options?.launcherVersion) {
200
+ for (const [extId, manifest] of byId) {
201
+ if (manifest.engines?.rynt) {
202
+ const v =
203
+ semver.coerce(options.launcherVersion)?.version ??
204
+ options.launcherVersion;
205
+ if (!semver.satisfies(v, manifest.engines.rynt)) {
206
+ const msg = `engines.rynt: host ${options.launcherVersion} does not satisfy ${manifest.engines.rynt}`;
207
+ errors[extId] = errors[extId] ? `${errors[extId]}; ${msg}` : msg;
208
+ byId.delete(extId);
209
+ }
210
+ }
211
+ }
212
+ }
213
+
214
+ const mergedDeps = mergeImpliedDependencies(byId, index);
215
+ const depVersionErrors = validateExtensionDependencyVersions(byId, mergedDeps);
216
+ for (const [id, msg] of Object.entries(depVersionErrors)) {
217
+ errors[id] = errors[id] ? `${errors[id]}; ${msg}` : msg;
218
+ }
219
+
220
+ const topoInput = new Map(
221
+ [...byId.keys()].map((id) => [
222
+ id,
223
+ {
224
+ id,
225
+ extensionDependencies: mergedDeps.get(id) ?? {},
226
+ },
227
+ ]),
228
+ );
229
+
230
+ const topo = topoSortExtensions(topoInput);
231
+ if (!topo.ok) {
232
+ return { ok: false, error: topo.error };
233
+ }
234
+
235
+ return {
236
+ ok: true,
237
+ order: topo.order.filter((id) => byId.has(id)),
238
+ errors,
239
+ index,
240
+ };
241
+ }
242
+
243
+ function applyContributesOrSkip(manifest: RyntExtensionManifestParsed): string | null {
244
+ return applyValidatedRyntContributesToManifest(manifest);
245
+ }
@@ -0,0 +1,103 @@
1
+ import type { Router, RouteRecordRaw } from 'vue-router';
2
+
3
+ import ExtensionRoutePage from './ExtensionRoutePage.vue';
4
+ import { useExtensionPageRegistry } from './registries/builtins/page';
5
+
6
+ export const EXTENSION_ROUTE_NAME_PREFIX = 'ext-route-';
7
+
8
+ export function isExtensionRouteName(name: unknown): name is string {
9
+ return typeof name === 'string' && name.startsWith(EXTENSION_ROUTE_NAME_PREFIX);
10
+ }
11
+
12
+ export function routeHasExtensionMeta(meta: unknown): boolean {
13
+ return (
14
+ meta !== null &&
15
+ typeof meta === 'object' &&
16
+ typeof (meta as { extensionId?: unknown }).extensionId === 'string'
17
+ );
18
+ }
19
+
20
+ const EXT_ROUTE_NAME_PREFIX = EXTENSION_ROUTE_NAME_PREFIX;
21
+
22
+ export function detachExtensionRoutes(router: Router): void {
23
+ detachExtensionRoutesForExtensions(router, null);
24
+ }
25
+
26
+ export function detachExtensionRoutesForExtensions(
27
+ router: Router,
28
+ extensionIds: string[] | null,
29
+ ): void {
30
+ const idFilter =
31
+ extensionIds && extensionIds.length > 0 ? new Set(extensionIds) : null;
32
+ const names = new Set<string>();
33
+ for (const r of router.getRoutes()) {
34
+ const n = r.name;
35
+ if (typeof n !== 'string' || !n.startsWith(EXT_ROUTE_NAME_PREFIX)) {
36
+ continue;
37
+ }
38
+ if (idFilter && routeHasExtensionMeta(r.meta)) {
39
+ const extId = (r.meta as { extensionId: string }).extensionId;
40
+ if (!idFilter.has(extId)) {
41
+ continue;
42
+ }
43
+ }
44
+ names.add(n);
45
+ }
46
+ for (const name of names) {
47
+ if (router.hasRoute(name)) {
48
+ router.removeRoute(name);
49
+ }
50
+ }
51
+ }
52
+
53
+ /** Маршруты из реестра `core.page` (после загрузки расширений). */
54
+ export function attachExtensionRoutes(router: Router): void {
55
+ attachExtensionRoutesForExtensions(router, null);
56
+ }
57
+
58
+ function buildExtensionRouteRecords(
59
+ extensionIds: string[] | null,
60
+ ): RouteRecordRaw[] {
61
+ const idFilter =
62
+ extensionIds && extensionIds.length > 0 ? new Set(extensionIds) : null;
63
+ const additions: RouteRecordRaw[] = [];
64
+ for (const { registryKey, value: page, extensionId: extId } of useExtensionPageRegistry().entries()) {
65
+ if (idFilter && !idFilter.has(extId)) {
66
+ continue;
67
+ }
68
+ additions.push({
69
+ path: page.resolvedRoutePath,
70
+ name: `${EXT_ROUTE_NAME_PREFIX}${encodeURIComponent(extId)}-${encodeURIComponent(registryKey)}`,
71
+ component: ExtensionRoutePage,
72
+ props: {
73
+ pageComponent: page.component,
74
+ extensionId: extId,
75
+ registryKey,
76
+ },
77
+ meta: { extensionId: extId },
78
+ });
79
+ }
80
+ return additions;
81
+ }
82
+
83
+ export function attachExtensionRoutesForExtensions(
84
+ router: Router,
85
+ extensionIds: string[] | null,
86
+ ): void {
87
+ for (const r of buildExtensionRouteRecords(extensionIds)) {
88
+ router.addRoute(r);
89
+ }
90
+ }
91
+
92
+ export function syncExtensionRoutesForExtensions(
93
+ router: Router,
94
+ extensionIds: string[],
95
+ ): void {
96
+ detachExtensionRoutesForExtensions(router, extensionIds);
97
+ attachExtensionRoutesForExtensions(router, extensionIds);
98
+ }
99
+
100
+ export function syncExtensionRoutes(router: Router): void {
101
+ detachExtensionRoutes(router);
102
+ attachExtensionRoutes(router);
103
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Токен сессии лаунчера для HTTP/WS из расширений.
3
+ * Отдельный entry (не корень `@rynt/sdk`): при сборке расширения `@rynt/sdk` остаётся external,
4
+ * bare specifier в браузере не резолвится — подставляется шим `@rynt/sdk/session`.
5
+ */
6
+ export { getSessionToken } from '../shared/api/graphql';
@@ -0,0 +1,23 @@
1
+ /** Стабильный сегмент URL для расширения (без спец-символов). */
2
+ export function extensionRouteSlug(extensionId: string): string {
3
+ return extensionId
4
+ .replace(/^@/, '')
5
+ .replace(/\//g, '__')
6
+ .replace(/[^a-zA-Z0-9._-]/g, '_');
7
+ }
8
+
9
+ export function normalizeExtensionSubpath(fragment: string): string {
10
+ const t = fragment.replace(/^\/+/u, '').replace(/\\/gu, '/');
11
+ if (t.includes('..') || (t.startsWith('.') && t !== '.')) {
12
+ throw new Error(
13
+ 'Extension navigation path must not escape its directory (. or ..)',
14
+ );
15
+ }
16
+ return t || 'page';
17
+ }
18
+
19
+ export function resolvedNavigationPath(extensionId: string, pathFragment: string) {
20
+ const slug = extensionRouteSlug(extensionId);
21
+ const tail = normalizeExtensionSubpath(pathFragment);
22
+ return `/ext/${slug}/${tail}`;
23
+ }
@@ -0,0 +1,147 @@
1
+ import semver from 'semver';
2
+
3
+ /**
4
+ * Текущая major-версия Extension API (манифест `extensionApi`: `"1"`).
5
+ * API только расширяется; старые расширения совместимы с новым хостом.
6
+ */
7
+ export const EXTENSION_API_VERSION = 1;
8
+
9
+ /**
10
+ * Разбирает `manifest.extensionApi` в целое major.
11
+ * Поддерживает `"1"`, `1`, legacy `"^1.0.0"` / `"1.0.0"` (берётся major).
12
+ */
13
+ export function parseExtensionApiMajor(value: unknown): number | null {
14
+ if (value === undefined || value === null) {
15
+ return null;
16
+ }
17
+ if (typeof value === 'number' && Number.isInteger(value) && value >= 0) {
18
+ return value;
19
+ }
20
+ const s = String(value).trim();
21
+ if (!s) {
22
+ return null;
23
+ }
24
+ if (/^\d+$/u.test(s)) {
25
+ return Number.parseInt(s, 10);
26
+ }
27
+ const coerced = semver.coerce(s);
28
+ return coerced ? coerced.major : null;
29
+ }
30
+
31
+ export interface CheckExtensionApiOptions {
32
+ /** При `true` и `required > host` возвращает blocking-сообщение. */
33
+ strict?: boolean;
34
+ }
35
+
36
+ export interface CheckExtensionApiResult {
37
+ ok: boolean;
38
+ /** Сообщение для `errors[id]` или лога. */
39
+ message?: string;
40
+ /** Блокировать загрузку расширения. */
41
+ blocking?: boolean;
42
+ /** Фактически используемая major (если поле опущено — 1). */
43
+ effectiveMajor: number;
44
+ }
45
+
46
+ /**
47
+ * Мягкая проверка Extension API: `required <= host` всегда OK;
48
+ * `required > host` — предупреждение, загрузка по умолчанию не блокируется.
49
+ */
50
+ export function checkExtensionApi(
51
+ manifest: { extensionApi?: string },
52
+ options?: CheckExtensionApiOptions,
53
+ ): CheckExtensionApiResult {
54
+ const host = EXTENSION_API_VERSION;
55
+ const parsed = parseExtensionApiMajor(manifest.extensionApi);
56
+
57
+ if (parsed === null) {
58
+ if (manifest.extensionApi !== undefined && manifest.extensionApi !== '') {
59
+ const legacy = String(manifest.extensionApi);
60
+ if (/[\^~<>=]/.test(legacy) || legacy.includes('.')) {
61
+ console.warn(
62
+ `[rynt/extensions] extensionApi «${legacy}» — устаревший semver-формат; используйте целое «${host}»`,
63
+ );
64
+ } else {
65
+ console.warn(
66
+ `[rynt/extensions] extensionApi «${legacy}» не распознан; считаем API ${host}`,
67
+ );
68
+ }
69
+ } else if (process.env.NODE_ENV !== 'production') {
70
+ console.warn(
71
+ `[rynt/extensions] extensionApi не указан; считаем API ${host}`,
72
+ );
73
+ }
74
+ return { ok: true, effectiveMajor: host };
75
+ }
76
+
77
+ if (parsed <= host) {
78
+ return { ok: true, effectiveMajor: parsed };
79
+ }
80
+
81
+ const message = `extensionApi: требуется API ${parsed}, лаунчер поддерживает ${host} — обновите лаунчер`;
82
+ const blocking = options?.strict === true;
83
+ if (!blocking) {
84
+ console.warn(`[rynt/extensions] ${message}`);
85
+ }
86
+ return {
87
+ ok: false,
88
+ message,
89
+ blocking,
90
+ effectiveMajor: parsed,
91
+ };
92
+ }
93
+
94
+ export interface NormalizeExtensionApiOptions {
95
+ /** Ошибка вместо приведения legacy semver к `"1"`. */
96
+ strict?: boolean;
97
+ extensionId?: string;
98
+ }
99
+
100
+ /**
101
+ * Приводит `manifest.extensionApi` к строке major (`"1"`).
102
+ * Возвращает текст ошибки или `null`.
103
+ */
104
+ export function normalizeExtensionApiInManifest(
105
+ manifest: { extensionApi?: string; id?: string },
106
+ options?: NormalizeExtensionApiOptions,
107
+ ): string | null {
108
+ const host = EXTENSION_API_VERSION;
109
+ const raw = manifest.extensionApi;
110
+ const label = options?.extensionId ?? manifest.id ?? 'extension';
111
+
112
+ if (raw === undefined || raw === null || String(raw).trim() === '') {
113
+ manifest.extensionApi = String(host);
114
+ if (process.env.NODE_ENV !== 'production') {
115
+ console.warn(
116
+ `[rynt/extensions] «${label}»: extensionApi не указан — подставлено «${host}»`,
117
+ );
118
+ }
119
+ return null;
120
+ }
121
+
122
+ const parsed = parseExtensionApiMajor(raw);
123
+ if (parsed === null) {
124
+ const msg = `extensionApi: не удалось разобрать значение «${String(raw)}»`;
125
+ if (options?.strict) {
126
+ return msg;
127
+ }
128
+ manifest.extensionApi = String(host);
129
+ console.warn(`[rynt/extensions] «${label}»: ${msg}; подставлено «${host}»`);
130
+ return null;
131
+ }
132
+
133
+ const legacy =
134
+ typeof raw === 'string' &&
135
+ (/[\^~<>=]/.test(raw) || (raw.includes('.') && !/^\d+$/u.test(raw.trim())));
136
+
137
+ if (legacy) {
138
+ const msg = `extensionApi «${raw}» — устаревший semver-формат, используйте «${parsed}»`;
139
+ if (options?.strict) {
140
+ return msg;
141
+ }
142
+ console.warn(`[rynt/extensions] «${label}»: ${msg}`);
143
+ }
144
+
145
+ manifest.extensionApi = String(parsed);
146
+ return null;
147
+ }
@@ -0,0 +1,33 @@
1
+ import { ref, type Ref } from 'vue';
2
+
3
+ import type { RyntExtensionHostOptions } from './extensions-init';
4
+ import { initializeRyntExtensions as runInitialize } from './extensions-init';
5
+
6
+ export function useRyntExtensionLoader(): {
7
+ isLoading: Ref<boolean>;
8
+ loadErrors: Ref<Record<string, string>>;
9
+ initializeRyntExtensions: (
10
+ options: RyntExtensionHostOptions,
11
+ ) => Promise<void>;
12
+ } {
13
+ const isLoading = ref(false);
14
+ const loadErrors = ref<Record<string, string>>({});
15
+
16
+ async function initializeRyntExtensions(
17
+ options: RyntExtensionHostOptions,
18
+ ): Promise<void> {
19
+ isLoading.value = true;
20
+ loadErrors.value = {};
21
+ try {
22
+ loadErrors.value = await runInitialize(options);
23
+ } finally {
24
+ isLoading.value = false;
25
+ }
26
+ }
27
+
28
+ return {
29
+ isLoading,
30
+ loadErrors,
31
+ initializeRyntExtensions,
32
+ };
33
+ }