Skip to content

Pass stable data dir to FW Lite to survive extension version updates#2385

Draft
imnasnainaec wants to merge 4 commits into
developfrom
pb-ext-stable-data-path
Draft

Pass stable data dir to FW Lite to survive extension version updates#2385
imnasnainaec wants to merge 4 commits into
developfrom
pb-ext-stable-data-path

Conversation

@imnasnainaec

@imnasnainaec imnasnainaec commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator

Platform.Bible runs each extension version from a versioned cache directory, so FW Lite's default of storing projects and auth cache relative to its binary would orphan data on every update. Pass explicit paths rooted at ~/.platform.bible/extensions/lexicon/ to keep data stable across versions.

Closes #2351

Devin: https://app.devin.ai/review/sillsdev/languageforge-lexbox/pull/2385

@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 20b707a5-0910-491b-aa85-754021f14477

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch pb-ext-stable-data-path

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@hahn-kev hahn-kev left a comment

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 looks correct to me

imnasnainaec and others added 4 commits June 30, 2026 11:18
Platform.Bible runs each extension version from a versioned cache directory,
so FW Lite's default of storing projects and auth cache relative to its binary
would orphan data on every update. Pass explicit paths rooted at
~/.platform.bible/extensions/lexicon/ to keep data stable across versions.

Closes #2351

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Platform.Bible actively rejects require() calls for non-papi modules at
runtime. Replace fs/os/path imports with process.env globals (which are
Node.js globals, not requires) and remove the pre-launch mkdirSync (FW
Lite creates its own data directories). Also reverts the incorrect
webpack externals change that made the build succeed but not the runtime.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@imnasnainaec imnasnainaec force-pushed the pb-ext-stable-data-path branch from 0fb240f to db851ab Compare June 30, 2026 15:19
@imnasnainaec

Copy link
Copy Markdown
Collaborator Author

The change is right-headed: the extension install dir is version-fluid, so pinning FW Lite data to a stable per-user path fixes real data loss. I verified the config keys bind correctly (LcmCrdt via LcmCrdtKernel.cs, Auth via FwLiteSharedKernel.cs), and that arg quoting is a non-issue (createProcess.spawn passes an argv array without shell: true, so spaces in USERPROFILE are fine — don't add quotes). Findings, most severe first:

1. Nothing creates the new directory — fresh installs break (blocking)

%USERPROFILE%\.platform.bible\extensions\lexicon won't exist on first run, and FwLiteWeb doesn't create ProjectPath at startup (the MAUI host does — FwLiteMauiKernel.cs:109). The old default only worked because it resolved to the exe's own directory, which always exists. With a missing dir:

  • CrdtProjectsService.ListProjects() calls Directory.EnumerateFiles(config.Value.ProjectPath, "*.sqlite") with no existence guard → DirectoryNotFoundException, so project listing 500s
  • CreateProject opens a SQLite connection at Path.Combine(config.Value.ProjectPath, ...) → Microsoft.Data.Sqlite doesn't create parent dirs → "unable to open database file"
  • MsalCacheHelper.CreateAsync opens a lockfile in the cache dir → sign-in can fail the same way

The extension can't mkdir itself (no fs access), so the cleanest fix is in FwLiteWeb startup: Directory.CreateDirectory on ProjectPath and the cache file's parent directory. That benefits every host, not just this one.

2. The chosen dir is PAPI's own storage root for this extension

When packaged, papi.storage.writeUserData for the lexicon extension writes to ~/.platform.bible/extensions/lexicon/user-data/<key> (paranext-core extension-storage.service.ts buildUserDataUri, with EXTENSION_DATA_DIR = 'extensions'). This PR points FW Lite's project root at the parent of that, so *.sqlite, msal.json, project-cache.json, and platform-managed storage share one directory with two owners. It coexists today (EnumerateFiles is non-recursive), but a fw-lite subdirectory (…\extensions\lexicon\fw-lite) would give the same stability with clean ownership.

3. "Mirrors Platform.Bible's own app:// convention" is only true when packaged

getAppDir() resolves app:// to ~/.platform.bible only when isPackaged; in development it's <paranext-core>/dev-appdata (src/node/utils/util.ts). So npm start development writes FW Lite data into the real user-profile tree while P.B itself uses dev-appdata — dev testing mutates production-location data, and wiping dev-appdata doesn't reset FW Lite state. Worth at least a doc-comment tweak.

4. Existing data isn't migrated

The old effective location was next to the exe: FwLiteWeb Program.cs does Directory.SetCurrentDirectory(AppContext.BaseDirectory) and the defaults are Path.GetFullPath(".") / Path.GetFullPath("msal.json"), i.e. <extension install>/fw-lite/. Anyone with local-only projects there sees them vanish and gets signed out after this update. Since the old location was already per-version this may be moot in practice, but if real users exist, a one-time copy-if-missing from the exe dir would rescue current data — or state in the PR that current users are known to be zero.

5. getFwLiteDataDir fallbacks

  • ?? '': if USERPROFILE is unset (service/CI contexts), the result is \.platform.bible\… — a drive-relative path that resolves to C:\.platform.bible\…. Better to throw than silently scatter data at the drive root.
  • ?? process.env.HOME: dead code — launchFwLite throws on non-win32 before this runs, and if that guard is ever lifted, the hardcoded backslashes produce a literal-backslash dirname in $HOME. Drop it, or build the path platform-aware.

AI-assisted review (Claude Code) posted on behalf of @imnasnainaec.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FwLiteWeb state is binary-relative, so every Platform.Bible extension update would orphan it

2 participants