Skip to content

Ecosystem merge#2113

Open
ebkr wants to merge 11 commits intodevelopfrom
ecosystem-merge
Open

Ecosystem merge#2113
ebkr wants to merge 11 commits intodevelopfrom
ecosystem-merge

Conversation

@ebkr
Copy link
Copy Markdown
Owner

@ebkr ebkr commented Apr 8, 2026

Ecosystem Merge

Adds support for loading from bundled ecosystem-schema.json, as well as loading from a ecosystem-merge.json which can exist on disk

Process

  • By default, we look for a merge file
    • If no merge file, we fall back to the bundled schema
  • Once we have loaded the schema, we (theoretically*) kick off an update to pull the latest schema
    • *This is actually just a stub for now as this functionality will be implemented later
  • Retrofit schema changes to applicable usages

TL;DR for reviews

  • Most of the work happens in EcosystemSchema.ts
  • ThunderstoreSchema.ts changes add reactive variables which can be referenced nicely inside of a Vue context. This means we can auto-update the game list as soon as we get a result without having to trigger an internal event.
    • Since all usages now use these reactive variables, we no longer have a need for the overall ThunderstoreSchema class. The file has been kept, but mostly as a holder for the variables and to keep the re-export functionality that it previously had. Out of scope to change that behaviour.
  • There is a boot file which is effectively a preload script. It happens before the screens are hit.
  • For the most part, the bundle loading logic was actually just copied sideways from the old implementation.
  • A couple of test fixes + new tests
    • Test fixes with ! changes are just to reduce type errors in the files

ebkr added 8 commits April 7, 2026 11:12
…tions post-boot.

- Start with bundled
- Next, load from disk
- Finally, should query live (not done yet)
- Fixed error caused by fetchLatestSchema stub not including valid keys
- Changed getMergedEcosystemPath to be more viable
- Enabled updateLatestMergedEcosystemSchema call in GameSelectionScreen
- Also removed EcosystemSchema class as no longer needed
- Replaced usages of EcosystemSchema getters with reactive equivalents.
@ebkr ebkr marked this pull request as ready for review April 9, 2026 08:46
Comment on lines +8 to +11
FsProvider.provide(() => NodeFsImplementation);
await updateEcosystemReactives();
// @ts-ignore
FsProvider.provide(() => undefined);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really awkward but I presume it's necessary?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically no, because we bind to the same provider later anyway, it's more just to keep a separation of concerns so that providers are all bound in the place you'd expect.

On the flip side, this (#2116) removes the need entirely and we can have all providers set before this is even ran.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Introduces a new ecosystem schema loading pathway that can hydrate Vue-reactive schema state from either a bundled schema or a cached schema on disk, and updates schema consumers/tests to use the new reactive sources.

Changes:

  • Added EcosystemSchema.ts to load/validate bundled schema, read an on-disk cached schema, and populate reactive exports.
  • Refactored schema consumers (game list, install rules, modloader variants) to read from reactive schema refs instead of a static class.
  • Added a Quasar boot step plus unit test updates/new tests to ensure the ecosystem reactives are initialized before use.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/r2mm/ecosystem/EcosystemSchema.ts New loader/validator + cache resolution that populates reactive ecosystem state
src/model/schema/ThunderstoreSchema.ts Replaces static schema class with Vue ref exports for supported games and modloader packages
src/r2mm/installing/profile_installers/ModLoaderVariantRecord.ts Reworks modloader exports to be derived from reactive schema state
src/r2mm/installing/InstallationRules.ts Uses reactive supported games to build rules
src/model/game/GameManager.ts Uses reactive game list source
src/boot/ecosystem.ts Boot-time initialization/hydration of ecosystem reactives
quasar.config.ts Registers new ecosystem boot file
src/pages/GameSelectionScreen.vue Adjusts flow to return after proceed() and stubs schema update call
test/vitest/tests/unit/EcosystemSchema/EcosystemSchema.spec.ts Adds coverage for cache fallback/version match and writing schema to disk
Various test/vitest/... specs/utils Ensures ecosystem reactives are initialized for unit tests

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +8 to +11
FsProvider.provide(() => NodeFsImplementation);
await updateEcosystemReactives();
// @ts-ignore
FsProvider.provide(() => undefined);
Comment on lines +74 to +88
let content: VersionedThunderstoreEcosystem;
try {
content = await getLastSavedEcosystemSchema();
} catch (e) {
const err = e as unknown as Error;
LoggerProvider.instance.Log(
LogSeverity.ERROR,
`Failed to load cached ecosystem schema, falling back to bundled schema\n${err.message}`
);
return bundledSchema();
}
if (!new VersionNumber(content.version).isEqualTo(ManagerInformation.VERSION)) {
return bundledSchema();
}
return content;
Comment on lines +18 to +20
async function getMergedEcosystemPath(): Promise<string> {
return path.join(PathResolver.ROOT, "latest-ecosystem-schema.json");
}
Comment on lines +43 to +48
async function loadBundledSchema(): Promise<ThunderstoreEcosystem> {
const ajv = new Ajv();
addFormats(ajv);

const validate = ajv.compile(jsonSchema);
const isOk = validate(bundledEcosystem);
Comment on lines +28 to +37
MODLOADER_PACKAGES = EcosystemModloaderPackages.value.map((x) =>
new ModLoaderPackageMapping(x.packageId, x.rootFolder, x.loader)
);
MOD_LOADER_VARIANTS = Object.fromEntries(
EcosystemSupportedGames.value
.map(([_, game]) => [
game.internalFolderName,
OVERRIDES[game.internalFolderName] || MODLOADER_PACKAGES
])
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants