Skip to content

[WIP] Add platform-specific filesystem compatibility adapters#5

Closed
Copilot wants to merge 1 commit into
v4from
copilot/add-platform-specific-adapters
Closed

[WIP] Add platform-specific filesystem compatibility adapters#5
Copilot wants to merge 1 commit into
v4from
copilot/add-platform-specific-adapters

Conversation

Copy link
Copy Markdown

Copilot AI commented Mar 12, 2026

Thanks for asking me to work on this. I will get started on it and keep this PR's description up to date as I form a plan and make progress.

Original prompt

Context

The v4 branch of touch-grass-bible already has a well-defined Files interface in src/external/Files.ts and a CapacitorFilesAdapter in src/external/CapacitorFiles.ts. There is also a FilesFromLocalStorage implementation and a Vault proxy class.

The app builds for multiple platforms:

  • Web (npm run build:web) — browser/PWA
  • Electron (npm run build:electron) — desktop (Node.js fs)
  • Capacitor (npm run build:capacitor) — Android & iOS

Currently, the Electron build has no native filesystem adapter — it would fall through to localStorage even though Electron's renderer has Node.js fs available. There is also no Node.js-native adapter that could be used for the Electron main process or for testing.

Goal

Create platform-specific filesystem compatibility adapters that implement the existing Files interface from src/external/Files.ts, so that each build target can be compiled with the correct adapter injected.

Tasks

1. src/external/ElectronFiles.ts — Electron (Node.js fs) adapter

Create a new file implementing Files using Node.js's fs/promises module. This will be used when the app is bundled for Electron.

Requirements:

  • Import Files, FileSystemItem, Folder, File (the class) from ./Files
  • Class name: ElectronFilesAdapter implements Files
  • Use import { readFile, writeFile, rename, rm, mkdir, access, constants } from "fs/promises" and import { join, dirname } from "path"
  • root: a Folder rooted at the user data path (app.getPath("userData") from Electron — accept a basePath: string constructor parameter instead so it stays decoupled from Electron internals)
  • readFile(path): fs/promises readFile with "utf-8" encoding
  • writeFile(path, data): ensure parent directories exist (mkdir recursive), then write
  • fileExists(path): use access with constants.F_OK, return true/false
  • rename(item): rename using the item's fullPath (uses the same path — no-op, as the caller is expected to have already updated the name property; preserve the original rename contract)
  • moveItem(item, newParent): rename from old full path to new full path
  • delete(path): rm with { recursive: true, force: true }
  • createFolder(path): mkdir with { recursive: true }
  • The root Folder should be initialized to the basePath provided in the constructor; override its fullPath so paths are resolved relative to basePath

2. src/external/NodeFiles.ts — Pure Node.js adapter (alias / re-export)

Create src/external/NodeFiles.ts that simply re-exports ElectronFilesAdapter as NodeFilesAdapter for clarity when used outside of Electron context (e.g., processing scripts, tests):

export { ElectronFilesAdapter as NodeFilesAdapter } from "./ElectronFiles"

3. src/external/WebFiles.ts — Web (localStorage) adapter alias

Create src/external/WebFiles.ts that re-exports the existing FilesFromLocalStorage as WebFilesAdapter for symmetry and clarity in web builds:

export { FilesFromLocalStorage as WebFilesAdapter } from "./Files"

4. src/external/PlatformFiles.ts — Platform detection bridge

Create src/external/PlatformFiles.ts that exports a createPlatformFiles() factory function. This function detects the runtime environment and returns the correct adapter:

import type { Files } from "./Files"

/**
 * Detects the platform at runtime and returns the appropriate Files adapter.
 * 
 * - Capacitor (iOS/Android): CapacitorFilesAdapter
 * - Electron (desktop): ElectronFilesAdapter
 * - Web / fallback: FilesFromLocalStorage (WebFilesAdapter)
 */
export function createPlatformFiles(basePath?: string): Files

Detection order:

  1. If window.Capacitor exists and window.Capacitor.isNative is true → use CapacitorFilesAdapter
  2. Else if window.require exists and calling window.require("electron") succeeds (Electron renderer) → use ElectronFilesAdapter with basePath or a sensible default
  3. Else → use FilesFromLocalStorage

Note: the actual import() of platform-specific adapters should be lazy/dynamic so that esbuild's tree-shaking can eliminate unused adapters per build target. Use dynamic import() for this reason. Since createPlatformFiles needs to be async in that case, make it return Promise<Files>.

Alternatively, if dynamic imports are complex to set up in the existing esbuild config, use static imports but wrap with try/catch for the Electron require detection. Document this in the file.

5. Update esbuild.config.mjs — add platform build flag

Modify esbuild.config.mjs to accept a second CLI argument (process.argv[3]) for platform target: web, electron, or capacitor. Use esbuild's define option to inject PLATFORM as a compile-time constant:

const platform = process.argv[3] ?? "web" // "web" | "electron" | "capacitor"
// Add to esbuild context options:
define: {
  "PLATFORM": JSON.stringify(platform)
}...

</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

*This pull request was created from Copilot chat.*
>

<!-- START COPILOT CODING AGENT TIPS -->
---

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more [Copilot coding agent tips](https://gh.io/copilot-coding-agent-tips) in the docs.

Copilot stopped work on behalf of TheJusticeMan due to an error March 12, 2026 00:31
@TheJusticeMan TheJusticeMan deleted the copilot/add-platform-specific-adapters branch March 12, 2026 00:43
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.

2 participants