Conversation
|
Adaptors now receive a pre-resolved StorePathSnapshot (nested typed Map keyed by OS and Base enums) scoped to the discovery, wrap it via createStorePathProvider, and return a GamePaths<T> map of concrete OS paths. The host forwards that map into getGameTools as plain data, so there is no symbolic mapping to cache and no per-resolve RPC chain. - adaptor-api: collapse SteamPathProvider|GOGPathProvider union into a single StorePathProvider; add Store/OS/Base enums and StorePathSnapshot; replace GameFolder/GameFolderMap with GamePaths<T>; rename resolveGameFolders -> paths; add createStorePathProvider and rehydrateGamePaths helpers for crossing the structured-clone boundary. - Generic IGamePathService<T> / IGameToolsService<T> so adaptors keep their extra key types through the pipeline. - main: build StorePathSnapshot per discovery with all Windows and Linux bases pre-resolved; expose via new adaptors:build-snapshot IPC. Proton support reserved via gameOS field (not yet detected). - renderer bridge: drop buildBasePaths/storeGameId/SerializedQualifiedPath; fetch the snapshot from the host, pass it to paths(), forward the opaque result to getGameTools. Caches reset on re-discovery. - shared: extend Serializable to include Map/Set (Electron's structured- clone IPC already preserves them). - cyberpunk2077: implement paths() against the snapshot; branch on gameOS for Windows vs Linux save locations.
Adaptors can now describe where each file in a mod archive should be
deployed by returning symbolic {source, anchor, destination} mappings,
where anchor is a key from the same adaptor's IGamePathService<T>. The
host resolves anchors to concrete QualifiedPaths at deployment time, so
installer logic stays OS- and path-agnostic.
- adaptor-api: new IGameInstallerService<T> and InstallMapping<T>
contracts. install() takes the same StorePathSnapshot that paths()
already receives, threaded through as a shared "game context" rather
than flat primitive args.
- @vortex/fs: new branded RelativePath type and relativePath()
constructor. Validates and normalizes (rejects absolute paths,
drive-letter prefixes, and .. segments; normalizes backslashes and
trims a trailing slash).
- renderer bridge: discovers /installer URIs by suffix, caches the
StorePathSnapshot alongside cached paths so install() can reuse it,
adds invokeInstaller, and exposes a renderer-side
adaptorInstallerRegistry keyed by gameId for a future InstallManager
integration. Adds a manifest warning when /installer or /tools is
declared without /paths.
- cyberpunk2077: reference installer that routes .ini to preferences,
.sav to saves, and everything else to the game install dir. Also
tightens paths() to reject native Linux discoveries, since no native
Linux build exists; gameOS must be Windows (Proton).
- adaptors.ts: Proton TODO on nativeToQualifiedPath documenting the
drive-letter regex edge case when a Wine-prefix path has not been
translated before being handed in.
InstallManager integration (registering as an IModInstaller and
translating anchor mappings into IInstruction[]) is deferred to a
follow-up PR.
Adaptors can now implement install() by declaring a list of glob
patterns instead of writing per-file routing logic. A shared
resolveStopPatterns() helper walks the archive's file list, picks the
first matching pattern per file, and emits the same InstallMapping<T>
the contract already consumes. Opt-in: adaptors that want bespoke
logic keep their imperative install().
- adaptor-api: new StopPattern<T> type with { match, anchor, destination? }.
destination can be omitted (destination = matched stable suffix of
the file path), a template with {source}/{match}/{basename}/{stem}/
{ext} placeholders, or a function for full control. Unmatched files
are silently dropped.
- adaptor-api: new glob matcher supporting **, *, ?, and {a,b,c}
alternation. Case-insensitive to align with Windows filesystem
semantics and classic Vortex stop patterns. A leading **/ marks a
pattern as wrapper-tolerant; the captured suffix becomes the
implicit destination, which gives classic "strip wrapping dir"
behaviour for free.
- cyberpunk2077: rewrite install() to use a 14-pattern CYBERPUNK_STOP_PATTERNS
list translated from the canonical paths in E1337Kat/cyberpunk2077_ext_redux.
Covers archive (canon/legacy/loose), CET, ReShade, Red4Ext, REDscript,
TweakXL, Audioware, r6 config XML/JSON, REDmod, and engine config/tools.
All mods install under Base.Game.
Note: this shares a name with Vortex's existing stop patterns (in
installer_fomod_shared/utils/gameSupport.ts) but has broader semantics.
Classic patterns are regex and only identify the mod root; these are
globs that also specify anchor + destination.
Takes a Nexus Mods mod URL, discovers the adaptor whose info.nexusMods domain matches, runs a real mod's archive file list through install(), and renders the resulting InstallMappings as a cli-table3 table. Useful for verifying that adaptor stop-pattern sets behave correctly on real-world mods without booting the full Vortex shell. Flow: parse URL -> resolve numeric gameId via data.nexusmods.com/.../games.json -> scan packages/adaptors/*/dist for the first adaptor whose getGameInfo reports a matching nexusMods domain -> load it in a Worker via createAdaptorHost -> call paths() against a synthetic Windows snapshot -> fetch mod files via the public api.nexusmods.com/v2/graphql modFiles query (unauthenticated) -> pull the archive manifest from file-metadata.nexusmods.com -> call install() -> render the mappings table. Runs via `npx tsx scripts/test-adaptor.ts <url>`. - cli-table3: added to the pnpm catalog and root devDependencies. - cyberpunk2077 build.mjs: narrow externals to exact root package names (`@vortex/adaptor-api`, `@vortex/fs`). Previously used `startsWith`, which externalized subpath imports like `@vortex/adaptor-api/contracts/game-installer`, but the adaptor sandbox at src/main/src/node-adaptor-host/bootstrap.ts only exposes the two root specifiers. Subpath modules now inline into the bundle. Safe because they only export pure helpers, not stateful singletons like the @provides registry.
- Reject unknown store and empty gamePath in adaptors:build-snapshot - Validate the adaptor install() response shape before returning - Make the installer registry module-private behind accessor functions - Document Serializable as Electron structured-clone (not JSON) semantics - Fix encodeURI -> encodeURIComponent in test-adaptor and document NEXUS_API_KEY
…narrowing
- Change GamePaths<T> from Map to plain mapped type { [K in T]: QualifiedPath }
so framework reads paths.game directly without null checks
- Move StorePathSnapshot wrapping into the worker dispatch layer so
adaptor methods receive StorePathProvider directly
- Add WindowsStorePathProvider/LinuxStorePathProvider discriminated union
with isWindows narrowing for compile-time OS-specific base safety
3b628fd to
2be15bf
Compare
|
I much prefer raw data over classes, but I get that approach doesn't line up with the rest of the new code design. Made the changes described. |
Summary
Introduces
IGameInstallerService, the adaptor contract that decides where each file in a mod archive should be deployed. Adaptors can implementinstall()directly or declare glob-basedStopPatternrules routed byresolveStopPatterns(). Cyberpunk 2077 ships with a concrete implementation covering the canonical mod layouts from the community redux extension.To feed the contract, the main process now assembles a
StorePathSnapshot(host OS, game OS, resolved bases per platform) at game discovery and hands it to the adaptor viaadaptors:build-snapshot. The renderer bridge caches the snapshot plus the resolvedGamePathsper game, and exposes a private installer registry throughgetAdaptorInstaller(gameId)for futureInstallManagerintegration.Adds
scripts/test-adaptor.ts, a CLI that pulls a mod's file list from Nexus and runs it through a chosen adaptor's installer, rendering the source/anchor/destination mapping as a table.Example run: Cyber Engine Tweaks
The unmapped files are the CET ASI loader itself (
cyber_engine_tweaks.asi,version.dll) plus a bareLICENSE. The current stop-pattern set does not yet route bootstrap DLLs/ASI files atbin/x64/, which is a known gap to address in a follow-up.