diff --git a/electron/login.html b/electron/login.html new file mode 100644 index 0000000..8f5ebe2 --- /dev/null +++ b/electron/login.html @@ -0,0 +1,136 @@ + + +
+ + +Sign in with your rokojori account
+ + + + + + + + + +Monday, 14 July 2026
++ Roject packaged as a standalone Windows desktop app with JWT-based auth, + token persistence, Authorization header injection, and a local Express server + running in-process. +
+electron/main.ts)
+ The Express server starts in-process inside Electron's main process via a
+ compiled startServer(port) export. A BrowserWindow
+ points at http://localhost:3000. The server's static file,
+ data, and locale paths all previously relied on __dirname
+ relative to the TypeScript source; a new source/server/rootDir.ts
+ module resolves these using process.env.ROJECT_ROOT (set by
+ Electron before starting the server) with a fallback that preserves the
+ existing ts-node behaviour.
+
+ A minimal electron/login.html form collects email and password.
+ Credentials are sent to the main process via IPC (contextBridge +
+ ipcRenderer.invoke). The main process calls
+ POST https://account.rokojori.com/api/auth/login directly using
+ Node.js https — no browser redirect, no CORS, no cookie.
+ Tokens are written to userData/tokens.json and reloaded on
+ the next app start.
+
+ session.defaultSession.webRequest.onBeforeSendHeaders intercepts
+ every request from the BrowserWindow to http://localhost:3000/*
+ and adds Authorization: Bearer <accessToken>. The
+ existing extractToken middleware already checked this header
+ (designed for Electron from the start), so the frontend required zero changes.
+
+ Server-side 302 redirects to
+ /api/auth/refresh-session are intercepted by
+ will-redirect — the main process calls
+ POST /api/auth/refresh with the refresh token, updates the
+ stored tokens, and reloads the original URL. A will-navigate
+ guard prevents the BrowserWindow from ever leaving localhost:
+ any external navigation (e.g. the app's login link pointing to
+ account.rokojori.com) is intercepted and replaced with the
+ Electron login window.
+
+ Three new tsconfigs: tsconfig.electron.json (compiles
+ electron/ → build/electron/),
+ tsconfig.electron-server.json (compiles
+ source/server/ → build/server/ for Electron's
+ in-process require). New npm scripts: electron:build,
+ electron:dev, electron:dist.
+ scripts/copy-electron-assets.js copies login.html
+ into build/electron/.
+ scripts/launch-electron.js spawns the Electron binary with
+ ELECTRON_RUN_AS_NODE deleted from the environment (VS Code /
+ Claude Code set this variable, which otherwise makes Electron behave as
+ plain Node.js with no GUI or API).
+
+ The outline originally described the server as a child process. Running it
+ in-process is simpler, removes IPC overhead, and is equivalent for the first
+ iteration. The compiled server JS is required at runtime via a dynamic
+ require(serverPath) call.
+
+ When this env var is set, the Electron binary runs as plain Node.js: no GUI,
+ no Electron API, require('electron') returns the binary path
+ string. The launcher script deletes it before spawning so the binary
+ initialises as a real Electron app. This was discovered by writing debug
+ output to a log file from inside the Electron process.
+
+ Six server files used path.join(__dirname, '..', '..', ...)
+ relative to the TypeScript source depth. Compiled output is one level deeper
+ (build/server/server/), breaking all paths. A single
+ rootDir.ts module exposes ROOT that all files
+ import, using ROJECT_ROOT when set (Electron) or the
+ __dirname fallback (ts-node).
+
+ The Express server reads JWT_SECRET from the environment.
+ When started via npm start this is provided by the shell; when
+ started from Electron there is no shell. A small inline loadEnv()
+ function in electron/main.ts parses the project-root
+ .env file and sets missing variables before startServer
+ is called.
+
+ Local filesystem access — extend the file tree to browse arbitrary directories
+ on the host machine using Node.js fs rather than the server's
+ JSON-backed project storage.
+
+ Remote projects in Electron — allow the Electron app to connect to a remote
+ Roject server (roject.rokojori.com) and list projects hosted
+ there alongside local ones. The JWT is already available; it's a matter of
+ pointing a request (or a BrowserView panel) at the remote URL with the token.
+
Electron desktop app shell — login window, JWT auth via API, Authorization header injection, token persistence, ROJECT_ROOT path fix, ELECTRON_RUN_AS_NODE workaround.
+rokojori-auth built and deployed; Roject local auth replaced with JWT middleware; CI/CD pipeline — webhook-based auto-deploy on push to main via /api/deploy.
diff --git a/workspace/outline/index.html b/workspace/outline/index.html index 963a358..787e862 100644 --- a/workspace/outline/index.html +++ b/workspace/outline/index.html @@ -91,38 +91,48 @@- Package Roject as a standalone desktop application using Electron. Since the - frontend is already plain HTML/JS/CSS, the Electron integration is mostly - structural: the Express server runs as a child process inside Electron's main - process, and the BrowserWindow is pointed at it. No frontend changes are needed - to make the existing UI run inside Electron. -
-
- Local filesystem access follows from this almost for free: the file tree is
- extended to browse arbitrary directories on the host machine using Node.js
+ The Electron shell is done (see below). The remaining work is extending the
+ file tree to browse arbitrary directories on the host machine using Node.js
fs directly, rather than being restricted to the
storage/<uuid>/root/ paths managed by the server. This is
what turns Roject from a hosted CMS into something closer to VS Code — the
user can open any folder on their machine as a project.
- These two features are treated as a single unit of work: there is no point - shipping Electron without local filesystem access, and local filesystem access - in the browser would require the File System Access API with significant UX - friction. Electron is the cleaner path. -
+ The Electron app currently runs a fully local Express server with its own
+ data store — it shares the same identity as the web version (via rokojori-auth)
+ but not the same projects. The next step is to allow the Electron app to also
+ connect to a remote Roject server (e.g. roject.rokojori.com) and
+ list, open, and edit projects hosted there, alongside any local filesystem
+ projects.
+
+ The Electron app already holds a valid JWT and can send it as an
+ Authorization: Bearer header. Connecting to a remote server is
+ therefore a matter of pointing a second BrowserWindow (or a panel in the
+ existing window) at the remote URL and injecting the token — no new auth
+ work needed.
+
Git integration inside the editor: file status indicators in the tree, staging, commit, push and pull, and eventually diffs and history. This depends on local @@ -146,7 +156,7 @@
A tunneling feature that allows local devices — a main workstation running Stable Diffusion, a local LLM, a GDScript language server, or any other @@ -174,6 +184,7 @@ entirely on the server, so it can be developed in parallel with the desktop work. It is placed here because its primary value is unlocked only once mobile access (feature 5) also exists. +
Make Roject usable on a phone or tablet. The quickest path given the existing web frontend is a Progressive Web App (PWA) — a manifest file and a service @@ -213,6 +224,40 @@
+ Roject runs as a standalone desktop application on Windows. The Express server
+ starts in-process inside Electron's main process. A custom login window
+ (electron/login.html) collects credentials and calls
+ POST https://account.rokojori.com/api/auth/login directly from
+ the main process — no browser redirect, no cookie. Tokens are stored in
+ userData/tokens.json and re-used across sessions.
+
+ All HTTP requests from the BrowserWindow to localhost have
+ Authorization: Bearer <accessToken> injected automatically
+ via session.webRequest.onBeforeSendHeaders — the frontend requires
+ zero changes. Expired tokens are refreshed via
+ POST /api/auth/refresh and the page is reloaded transparently.
+ Any navigation away from localhost is intercepted and redirected
+ to the Electron login window instead.
+
+ Known issue: ELECTRON_RUN_AS_NODE=1 is set by VS Code / Claude
+ Code, which makes Electron behave as plain Node.js. The launcher script
+ (scripts/launch-electron.js) deletes this variable before
+ spawning the binary. Run with npm run electron:dev or
+ node scripts/launch-electron.js after the build.
+