Commit Graph

4 Commits

Author SHA1 Message Date
Keysat 25b1c3a366 Add free tier (unlicensed users get one-at-a-time summarization)
Unlicensed users can now summarize a single video at a time using their
own Gemini API key. The result renders in the UI exactly like a paid
summary, but is not persisted — there's no library entry, no history,
and a second submission while one is in flight is rejected.

Server (server/index.js):
  • /api/process is now in LICENSE_OPEN_PATHS. The route handler
    distinguishes free users (state !== "licensed" || no "core") and:
      - rejects USE_SERVER_KEY / empty key with 402 byo_key_required
        (so the bundled Gemini key stays paid-only)
      - rejects a second concurrent job with 409 processing_in_progress
        via a module-level freeJobInFlight flag, released in finally
      - skips saveToHistory so the host's library stays clean
  • Pro feature gates (history/library/subscriptions) unchanged — still
    return 402 feature_not_in_tier for unlicensed callers.

Frontend (public/index.html):
  • New state.activationSkipped flag (persisted to localStorage). The
    activation screen still appears on first launch, but now offers a
    "Skip — use free mode" button alongside Activate / Buy a key.
    Once skipped, the main app renders normally.
  • Free-mode upgrade banner under the top bar with Upgrade and "I have
    a key" buttons (the latter routes back to the activation screen).
  • handleLibraryClick / handleSubscribeClick wrappers — for unlicensed
    users, the library (clock) icon and the channel-URL Subscribe
    submission show a toast explaining the upgrade rather than opening
    an empty sidebar / hitting a 402.
  • Submit button enforces BYO key for unlicensed users (the bundled
    state.hasServerKey doesn't enable submit). handleSubmit shows a
    toast when an unlicensed user tries to queue a second video.
2026-05-08 11:16:02 -05:00
Keysat 7d71150439 Fix SSE event type lost across reader chunks (blank screen post-process)
Symptom: after a long video finishes processing, the screen goes blank
even though the video and chunks save correctly to history (visible
after a refresh + library click).

Cause: the manual SSE parser in processUrl declared `let eventType = ""`
inside the `while (await reader.read())` loop, so the variable reset on
every chunk. The server emits each event as a single write of
`event: X\ndata: Y\n\n`, but for a long video the result payload (entries
+ chunks + logs) is tens of KB and gets split across reader chunks by
the browser. When the split landed between the `event: result\n` line
and the `data: ...` line, the event type was lost and `handleSSE("",
data)` matched no branch — the result event was silently dropped, and
state.chunks stayed at the empty array set during processUrl reset.

Fix: hoist eventType outside the loop so it persists across chunks, and
reset it after each dispatch (per the SSE spec, event type returns to
default after an event is fired).

Short videos with small result payloads fit in a single chunk and so
were unaffected — which is why the bug looked intermittent.
2026-05-08 11:04:50 -05:00
Keysat 574a16d9fa Save in-progress keysat integration and StartOS 0.4 work
Snapshot of the working tree before cleanup. Captures:
- Keysat licensing: server/license.js, /api/license/* endpoints in
  server/index.js, activation modal in public/index.html, embedded
  Ed25519 issuer key (assets/issuer.pub).
- StartOS 0.4 expansion: setApiKey action, version files v0.1.1
  through v0.1.15, file-models/config.json.ts, manifest updates.
- Self-hosted registry server (startos-registry/).
- Build/deploy scripts (bin/bump-version.sh, bin/deploy.sh, vendored
  yt-dlp binary), .gitignore, .deploy.env.example.
- Recent design docs (KEYSAT_INTEGRATION.md, UPGRADE-DESIGN.md) —
  retained here so they remain recoverable when removed in the
  follow-up cleanup commit.
2026-05-08 09:39:17 -05:00
MacPro 68ec875ee7 Add StartOS 0.4.0 packaging 2026-04-09 15:03:31 -05:00