Skip to content

Releases: Suydev/isotope-code

v3.3.7 — Auth-gated sync state machine; stop infinite retry on auth failure

08 Jun 02:49

Choose a tag to compare

[3.3.7] — 2026-06-08 — Fix: auth-gated sync state machine; stop infinite retry on auth failure

Fixed (sync state machine — complete rebuild)

  • Auth failure is now a STOP condition, not a retry condition — Previously any auth error (expired session, no session, 401) caused the sync to be written as failed and retried on the next timer tick, visibility change, or online event. The same 2009 KB payload would upload infinitely. Now any auth error immediately sets __isoSyncAuthBlocked = true and the entire sync pipeline halts.
  • New isAuthError / isPermissionError / isNetworkError classifiers — Errors are classified before deciding to stop vs. retry. Network errors still retry; auth and permission errors do not.
  • authedJson now throws tagged AuthError objects — When JWT is null or refresh fails, the thrown Error has __isAuthError = true. When the server returns 401/auth message, the thrown error is also tagged. All callers can now distinguish the error type.
  • 30-min timer stops on auth failure, restarts on recovery__isoSyncAuthBlock() calls clearInterval(_autoSyncTimer). __isoSyncAuthUnblock() restarts it and schedules one sync attempt.
  • All sync triggers check auth-blocked state__isoAutoSync, __isoStartupSync, the 30-min timer interval, the visibility-change handler, and the online-event handler all check window.__isoSyncAuthBlocked and return { reason: 'paused_auth' } without running any upload/download.
  • Token intercept unblocks sync on new valid session — When Supabase returns a new access_token (login, token refresh), the fetch interceptor calls window.__isoSyncAuthUnblock(), which clears the blocked flag, restarts the timer, and queues one sync attempt 2 s later.
  • Login (__isoLogin) unblocks sync on success — After a successful username/password login and profile sync, __isoSyncAuthUnblock() is called so sync resumes without waiting for the next Supabase token intercept.
  • Online event re-validates session before unblocking — When the network comes back and __isoSyncAuthBlocked is true, the handler calls getValidJwt() first; if a valid JWT exists, it unblocks and syncs. It does not blindly retry the upload.
  • Smart-sync catch re-throws auth errors — The try/catch around /__auth/backup/latest in __isoRunManualCloudSync previously swallowed all errors as "non-fatal". Now auth errors are rethrown so they propagate to the outer catch and trigger the block.
  • Permission errors get a distinct failed_permission status — These are written to sync metadata and history separately; they never trigger a retry.
  • All sync operations (snapshot, upload, download_import, manual_sync) handle auth errors uniformly — Each catch block calls __isoSyncAuthBlock() and writes paused_auth to sync history instead of failed.

Audit (v3.3.7 — 2026-06-08)

# Check Result
1 Auth failure stops all scheduled sync ✅ fixed
2 Same payload never uploads infinitely on auth error ✅ fixed
3 30-min timer cleared on auth failure ✅ fixed
4 Timer restarted on new valid session ✅ fixed
5 All sync triggers check __isoSyncAuthBlocked ✅ fixed
6 Token intercept calls __isoSyncAuthUnblock() ✅ fixed
7 Login success calls __isoSyncAuthUnblock() ✅ fixed
8 Auth vs network vs permission errors classified ✅ fixed
9 Smart-sync auth errors propagate instead of being swallowed ✅ fixed

v3.3.6 — Cloud sync download fix; storage cleanup; setup improvements

08 Jun 02:36

Choose a tag to compare

[3.3.6] — 2026-06-08 — Fix: cloud sync download on new device; storage cleanup; setup improvements

Fixed

  • CRITICAL: Cloud backup never downloaded on new/different deviceGET /__auth/backup/latest returned the backup JSON but omitted the cloud_snapshot field when serving from the exports/latest.json path (the primary path). The client smart-sync reads cloudData.cloud_snapshot.exported_at to compute cloudTs. Without it, cloudTs = 0 so the cloudIsNewer check (!localTs && cloudTs > 0) was always false on a new device — the cloud backup was fetched but never applied. Fix: the endpoint now also fetches cloud-snapshot/latest.json and includes it in the response on every path.
  • CRITICAL: Download skipped on startup (timing race)window.__isoBuildBackup and window.__isoApplyBackup are registered by the app bundle's internal sync method, which fires asynchronously after React initialises. The startup sync (previously 5 s after page load) frequently fired before these were set, falling back to an upload-only snapshot and never downloading cloud data. Fix: startup delay increased to 8 s; __isoAutoSync now polls for the functions for up to 15 additional seconds before falling back, giving the app enough time to register them.
  • First-sync debounce blocks retry — If the startup sync fell back to upload-only on a new device (no download), the 5-minute debounce was already written, preventing retry on the next page load. Fix: when a first-sync (no local snapshot history) completes without a download, the debounce timestamp is cleared so the next page load retries.
  • New-device fallback bootstraps from cloud — In the upload-only fallback path, if the device has no local sync history, the server now calls /__auth/bootstrap first to restore the cloud snapshot into Supabase DB before uploading a snapshot. This ensures the snapshot reflects actual cloud state even when build/apply fns were never registered.

Fixed (storage)

  • Old cloud backup files accumulating in StorageuploadRawUserBackupJson wrote a new timestamped file ({userId}/exports/YYYY-MM-DD....json) on every upload but never deleted old ones. Fixed: after each upload, old timestamped files in the same folder are pruned in the background, keeping only the 3 most recent.
  • Cloud snapshot history files accumulatinguploadCloudSnapshotForUser wrote history snapshots ({userId}/cloud-snapshot/history/....json) that were never cleaned up. Fixed: after each history write, files are pruned keeping only the 5 most recent.
  • New supaStorageListAsUser helper — Implements POST /storage/v1/object/list/{bucket} using user-scoped JWT + anon key, used by the new pruning logic.

Improved (setup)

  • setup.sh installs Node.js 18+ on Debian/Ubuntu via NodeSource — Previously used apt-get install nodejs which installs the distro-packaged version (often v12). Now checks the installed version first; if < 18, fetches the NodeSource v22 setup script and uses that, falling back to nvm or a clear error.
  • setup.sh works non-interactively--yes / -y flag and piped stdin now skip all prompts reliably.

Audit (v3.3.6 — 2026-06-08)

# Check Result
1 cloud_snapshot included in all /__auth/backup/latest responses ✅ fixed
2 Startup sync polls up to 15 s for build/apply fns before fallback ✅ fixed
3 First-sync debounce cleared when download didn't happen ✅ fixed
4 Fallback path calls /__auth/bootstrap on new device ✅ fixed
5 Old export files pruned after upload (keep 3) ✅ fixed
6 Old snapshot history files pruned after upload (keep 5) ✅ fixed
7 supaStorageListAsUser helper implemented ✅ added

IsotopeAI v3.3.5 🧪

07 Jun 15:32

Choose a tag to compare

IsotopeAI v3.3.5

Fixed

  • CRITICAL: /api/health?_=<timestamp> speed probe returned HTTP 404 — The network speed probe fired by the app at every session used a cache-busting query-string (?_=Date.now()). The API health handler matched req.url === '/api/health' (exact string), so any request with a query string silently fell through to the /api/* 404 fence added in v3.3.4. The speed probe received {"ok":false,"error":"Not found"} (34 B) instead of the ~230 B health payload, making the sync timeout calculator classify every user as "slow" (150 s timeout). Fixed: all /api/* route handlers now match adminPath (the URL parsed without query string) instead of the raw req.url.
  • Same query-string fallthrough for /api/version, /api/check-update, /api/ai-config — All four API route handlers were patched from req.url === to adminPath ===.

Performance

  • Health endpoint caching (15 s TTL)/api/health previously made 3 concurrent Supabase HTTP round-trips on every call (REST, Auth, Storage), taking 200–600 ms. Results are now cached for 15 seconds; subsequent calls return in <1 ms. The cache is only populated on a successful ok response so degraded states still probe live.
  • Pre-gzip bundle cache — 10 major JS bundles (App, Auth, Focus, Onboarding, SingleGroup, Leaderboard, Settings, AppAccessGate, SessionSync, Invites) are gzip-compressed once at server startup and stored in memory (_gzipCache). All subsequent requests for these assets skip the per-request zlib.gzip() call and serve the cached compressed buffer instantly. For all other hashed immutable assets and SW files, the first gzip result is also cached.
  • 14 missing database indexes added (performance-indexes.sql) — Static schema analysis found 14 unindexed foreign-key and date-ordering columns:
    • community_events(creator_id), community_events(host_user_id) — FK columns never indexed
    • community_events(created_at), community_events(updated_at) — date ordering
    • user_tours(user_id) — FK for guided-tour lookups per user
    • user_tours(created_at), user_tours(updated_at) — date ordering
    • user_roles(granted_by) — FK for admin audit queries
    • group_invites(created_at) — expiry + ordering queries
    • group_challenges(created_at) — ordering
    • groups(created_at), groups(updated_at) — ordering
    • users(updated_at) — profile sync delta queries
    • Apply via: Supabase Dashboard → SQL Editor → run performance-indexes.sql

Added

  • performance-indexes.sql — New file containing all 14 CREATE INDEX IF NOT EXISTS statements. Idempotent and safe to run multiple times. Referenced from admin panel setup guide.

Audit (v3.3.5 — 2026-06-07)

# Check Result
1 /api/health?_=timestamp speed probe now returns 200 JSON ✅ fixed (adminPath match)
2 /api/version, /api/check-update, /api/ai-config same fix ✅ all 4 handlers patched
3 Health endpoint cached at 15 s TTL ✅ <1 ms on cache hit
4 10 bundles pre-gzip'd at startup _gzipCache Map
5 14 missing indexes documented in performance-indexes.sql ✅ new file
6 All changes pushed to GitHub


📥 Quick Install

git clone https://github.com/Suydev/isotope-code.git
cd isotope-code
bash setup.sh

📋 What's Changed

See CHANGELOG.md for the full history.

❤️ Support

UPI: 9699393886@fam · isotopeai.in

v3.3.0 — Live DB RLS patch, GitHub Pages docs link, login error improvements

07 Jun 12:20

Choose a tag to compare

What's new in v3.3.0

Fixed

  • §5+§6 RLS policies applied to live Supabase DB — Own-row RLS optimisation (§5) and leaderboard public-read policies (§6) from performance-patch.sql applied to the live database via the Management API. Leaderboard now works correctly for authenticated users. Tables patched: users, user_profiles, user_points, user_stats_summary, daily_user_stats, study_sessions_log, notifications, user_presence, groups, group_members, group_chat_messages, group_challenges, group_challenge_participants, group_announcements, group_invites, group_milestones.
  • Improved login error messages (/__auth/login) — Login failures now surface the specific Supabase error: "email not confirmed" shows a confirmation-link hint; "invalid credentials" shows a clear message directing users to their Supabase-registered email and password. Previously all failures returned a generic message.

Added

  • GitHub Pages docs badge on login screen (server.mjs DOCS_LINK_HTML) — A 📖 Docs badge is injected into every served HTML page (including the unauthenticated login screen) in the bottom-right corner, linking to https://suydev.github.io/isotope-code/
  • README updated — Logo in README header now links to GitHub Pages; Docs badge and nav link added to the header; footer updated with Documentation link; version badge updated to 3.3.0.
  • GitHub Pages docs updated (docs/index.md) — Added v3.3.0 changelog section, GitHub Pages self-link, repository link, and updated version footer.

Audit summary

Check Result
Total assets scanned 211 (191 non-font)
/api/broadcast in vendor-supabase bundle ✅ Supabase realtime internal — not a server route
All /__auth/* server endpoints ✅ login, signup, backup, backup/latest, snapshot, profile, refresh, delete-account
All /api/* server endpoints ✅ version, healthz, status, config, export, ai/*, pwa-events, proxy
§5 own-row RLS applied to live DB ✅ 6 batches × HTTP 201
§6 leaderboard public-read policies ✅ stats_select_all, daily_select_all, users_select_display
Missing tables (user_inventory, community_events) ℹ️ Not in live schema — SQL skipped safely

Full changelog: https://github.com/Suydev/isotope-code/blob/main/CHANGELOG.md
Documentation: https://suydev.github.io/isotope-code/

v3.2.0 — Leaderboard RLS fix + SQL index correction

07 Jun 11:32

Choose a tag to compare

What changed

Fixed

  • Leaderboard shows empty rankings — All 5 leaderboard REST queries now use the authenticated user JWT instead of the bare ANON key. The §5 RLS hardening had set user_stats_summary, daily_user_stats, and users to "own row only"; the ANON key has auth.uid() = NULL so every query returned 0 rows. Authenticated users now see full community rankings.
  • SQL index creation fails silentlyperformance-patch.sql §4 referenced a column study_minutes that does not exist on daily_user_stats (correct name: seconds_studied). The index idx_daily_user_date_minutes silently failed on every fresh install. Corrected.

Added

  • performance-patch.sql §6 — Three new leaderboard-compatible RLS policies: stats_select_all (authenticated users can SELECT all rows in user_stats_summary), daily_select_all (authenticated users can SELECT all rows in daily_user_stats), users_select_display (anyone can SELECT id, username, name, avatar_url from users). Own-row write restrictions from §5 remain in effect.

Upgrading

  1. Pull the latest code: git pull
  2. Apply the updated performance-patch.sql in Supabase SQL Editor (the §6 block at the end adds the three new policies — safe to re-run, all statements are idempotent).
  3. Restart the local server: isotope restart

v3.1.3 — Performance Hardening & Professional Release

06 Jun 05:17

Choose a tag to compare

What's New in v3.1.3

🛡️ Supabase RLS Performance Hardening (Advisor Fix)

All 20+ Row-Level Security policies now use (SELECT auth.uid()) instead of auth.uid() directly. This is the #1 Supabase Performance Advisor recommendation — it forces PostgreSQL to evaluate the auth function once per query rather than once per row, eliminating a major source of RLS overhead on every authenticated read.

⚡ PWA Server-Check Polling Fixed

public/pwa-local.js replaced the aggressive 10-second setInterval server poll with a visibility-change listener and a 5-minute background keepalive. The server is now checked only when the user returns to the tab, not constantly in the background.

📁 .env.example Added

The .env.example file was missing entirely — causing setup.sh and setup.bat to fail on fresh clones. It is now included with all required and optional fields documented.

🪟 update.bat Added

Windows users now have an update.bat shortcut in the repo root that delegates to isotope update or the local wrapper.

📊 performance-patch.sql — Complete RLS Policy Replacement

Section §5 of performance-patch.sql now DROP/CREATE-replaces all affected policies with the optimised (SELECT auth.uid()) pattern. Safe to re-run.

How to Update

isotope update

Files Changed

File Change
.env.example Added (was missing)
update.bat Added (Windows update shortcut)
performance-patch.sql §5 added: full RLS auth.uid() → (SELECT auth.uid()) migration
public/pwa-local.js 10s polling → visibility-change + 5min keepalive
.gitignore Added !.env.example exception
CHANGELOG.md v3.1.3 entry
README.md Badge updated to v3.1.3
VERSION Bumped to 3.1.3
package.json Version 3.1.3

v3.1.2 - Storage-backed backup restore

06 Jun 04:37

Choose a tag to compare

v3.1.2

  • Connect Settings/Data & Privacy Cloud Sync to the real browser-generated backup JSON from the compiled exporter.
  • Store the full backup JSON in user-content exports/latest.json and embed it into cloud-snapshot/latest.json as local_backup/backup_data.
  • Restore local collections from Storage backup JSON through the compiled importer instead of querying missing tasks/subjects/focus_sessions/habits/exams/daily_logs/tests tables.
  • Add cloud-snapshot fallback for /__auth/backup/latest when exports/latest.json is absent.
  • Auto-import the cloud backup on empty/cache-cleared authenticated devices during app bootstrap.
  • Update sync proof docs to mark local collections as Storage-backed, not fake DB table sync.

v3.1.1 - Real cloud backup pipeline

06 Jun 04:01

Choose a tag to compare

v3.1.1

  • Upload the real browser-generated backup JSON from Settings/Data & Privacy sync flows into Supabase Storage under user-content.
  • Download and import the latest full cloud backup during cloud restore instead of trusting local browser cache.
  • Refresh canonical cloud snapshots after profile, onboarding, avatar, study session, and manual backup changes.
  • Use deterministic avatar object paths with SHA-256 and clean older owned avatar objects to avoid repeated duplicates.
  • Fix login persistence across local server restarts by restoring refresh-token sessions and enabling Supabase token auto-refresh.
  • Tighten Storage RLS policies for avatars, user-content, and notes so authenticated users manage only their own paths.
  • Add trace/proof documentation for cache-clear cloud restore checks.

IsotopeAI Local v2.9.0

04 Jun 16:06

Choose a tag to compare

IsotopeAI Local v2.9.0

This release packages IsotopeAI as portable local software: users run the app on their own device, while Supabase provides shared cloud sync for auth, profiles, onboarding, community, events, storage, leaderboard, notifications, and realtime.

Highlights

  • Default public Isotope Supabase URL and anon key for normal installs.
  • Normal users do not need service-role keys, admin secrets, Supabase PATs, or GitHub PATs.
  • Smarter first-run setup scripts for Windows, macOS, Linux, and Termux.
  • Safer update scripts that preserve .env and stash local changes.
  • GitHub Pages docs rewritten for the local software model.
  • Startup output now shows local app/cloud sync status instead of admin-disabled noise.
  • Missing JS asset recovery from upstream /assets/.js sources.
  • Onboarding/login and stale fake-subject protections remain included.

Verified

  • node server.mjs starts in normal local app mode.
  • Supabase REST/Auth/profile/onboarding/community-events are reachable.
  • Storage buckets avatars, event-images, user-content, and notes exist.
  • Upload, download, signed URL, and cleanup passed for all four buckets.
  • /api/community-events returns widget-safe event data.
  • Tracked-file secret scan is clean for service-role/admin/GitHub secrets.

Security

Repository history was previously reset to a sanitized root commit. Any token that was ever exposed should still be revoked and regenerated.