Multi-provider addon and user management for Stremio & Nuvio
Fork of iamneur0/syncio — see README.upstream.md for the original documentation.
This fork adds Nuvio as a second provider alongside Stremio, along with security hardening, bug fixes, and cross-platform dev improvements. The core Syncio functionality (groups, addons, sync engine) is unchanged — a provider abstraction layer routes operations to either Stremio or Nuvio based on each user's providerType.
The main feature. Users can now be connected via Nuvio (Supabase-backed) instead of Stremio.
A factory function createProvider(user, deps) returns a uniform interface regardless of provider:
getAddons() setAddons(addons) addAddon(url, manifest) clearAddons()
getLibrary() addLibraryItem(...) removeLibraryItem(...)
getLikeStatus(...) setLikeStatus(...)
Stremio provider wraps StremioAPIClient. Nuvio provider uses Supabase REST. The sync engine, addon management, and all route handlers work identically with either.
Two auth flows for Nuvio:
- OAuth device-code flow — user scans a QR code / visits a URL on another device, polls for approval. Used in the login page and invite flow.
- Email + password — direct credential validation against Supabase auth. Used in the user add modal.
Auth is module-level (not on the provider instance) — nuvioAuth.js handles validate, token refresh, and the TV login flow.
- Nuvio refresh tokens are encrypted at rest (same as Stremio auth keys)
- Access tokens auto-refresh on expiry with a 60-second buffer
- New refresh tokens are persisted back to the database automatically via
onTokenRefreshcallback
- Same email can exist as both a Stremio and Nuvio user (unique constraint now includes
providerType) - User uniqueness checks are scoped by provider to prevent cross-provider conflicts
- Fingerprint comparison uses URL-only mode for Nuvio users (Syncio controls the URL set)
server/providers/
index.js # Factory: createProvider(user, deps)
stremio.js # Wraps StremioAPIClient
nuvio.js # Supabase REST calls
supabase.js # Low-level PostgREST HTTP helper
stremioAuth.js # Re-exports existing Stremio auth
nuvioAuth.js # Validate, refresh, TV login flow
server/routes/nuvio.js # /api/nuvio/* endpoints
- OAuth session rate limiting — max 3 pending OAuth sessions per IP, auto-expiring after 5 minutes
- Tightened error responses — error messages no longer leak internal details; only
error.messageis logged server-side - PROVIDER_AUTH_EXPIRED — graceful handling when provider tokens expire (returns 401 instead of 500)
- Provider-scoped validation — user checks include
providerTypeto prevent cross-provider conflicts - Removed debug logging — stripped
console.logstatements from auth flows and provider operations
- Provider selection in user add/edit modals — toggle between Stremio and Nuvio with auth state reset on switch
- NuvioOAuthCard — device-code flow component with QR code, polling, auto-retry on expiry
- NuvioLoginCard — email/password form with validation state tracking
- Provider badges on user cards showing Stremio or Nuvio
- Genericized strings — "Stremio account" → "account", "Wrong Stremio Account" → "Wrong Account", etc.
- Email mismatch handling in invite flow — specific error state instead of generic toast
- Cache invalidation — addon query caches are invalidated after sync operations
Three new fields on the User model:
providerType String @default("stremio") // "stremio" | "nuvio"
nuvioRefreshToken String? // Encrypted Supabase refresh token
nuvioUserId String? // Supabase user UUIDUpdated unique constraint: @@unique([accountId, email, providerType]) on Postgres, @@unique([email, providerType]) on SQLite — allows the same email across different providers.
Docker users: The container runs migrations automatically on startup. Just pull the new image and restart.
Local dev users: Run the migration manually after pulling:
# PostgreSQL
cross-env DATABASE_URL=postgresql://syncio:syncio@localhost:5432/syncio npx prisma db push --schema prisma/schema.postgres.prisma
# SQLite
cross-env DATABASE_URL=file:./prisma/sqlite.db npx prisma db push --schema prisma/schema.sqlite.prisma- Added
cross-envandshx— cross-platform env variable setting and shell commands (Windows compatibility) - npm scripts updated to use
shx cpandcross-envinstead of Unix-specificcpand bare env vars
- Simplified
metricsBuilder.jsandactivityMonitor.jsprovider handling - Bug fixes in invite flow (email mismatch, renewal page)
RequestRenewedPagecomponent for renewed invite handling- Nuvio connect endpoint now sets
isActive: trueon the user - Username generation capped at 100 attempts to prevent infinite loops
- Removed legacy test scripts (custom test suites replaced upstream)