Skip to content

[codex] gate app access behind subscription#3846

Merged
louis030195 merged 2 commits into
mainfrom
codex/app-pricing-gate
Jun 5, 2026
Merged

[codex] gate app access behind subscription#3846
louis030195 merged 2 commits into
mainfrom
codex/app-pricing-gate

Conversation

@louis030195

Copy link
Copy Markdown
Collaborator

What changed

  • Adds a desktop app entitlement helper and global app gate that requires login plus active app access in production.
  • Keeps bun tauri dev / debug builds unblocked while removing the production onboarding skip path.
  • Extends the desktop user payload with app_entitled, subscription_plan, and entitlement, while preserving legacy cloud_subscribed access during rollout.
  • Adds native guards so app auto-start, manual capture start, and restart paths refuse to start recording without entitlement.
  • Stops the running engine when the entitlement gate activates after sign-out or lost access.

Why

The website pricing PR introduces Standard/Pro/Enterprise app entitlement. The desktop app needs to consume that contract so unpaid or signed-out production users cannot keep using local capture while dev remains workable.

Validation

  • bunx next lint --file components/app-entitlement-gate.tsx --file lib/app-entitlement.ts --file components/onboarding/login-gate.tsx --file lib/hooks/use-settings.tsx --file lib/auth-guard.tsx --file app/providers.tsx --file lib/utils/validation.ts
  • bun run bindings:check
  • git diff --check origin/main..HEAD

Note: the clean worktree needed ignored local build resources copied from the main checkout (bun-aarch64-apple-darwin, ffmpeg-aarch64-apple-darwin, ffprobe-aarch64-apple-darwin, screenpipe-aarch64-apple-darwin, ui_monitor-*) plus an ignored out/ folder for the Tauri binding check. Those are not part of the PR diff.

@louis030195 louis030195 force-pushed the codex/app-pricing-gate branch 2 times, most recently from 279707c to d2f5ff9 Compare June 5, 2026 14:46
@louis030195 louis030195 force-pushed the codex/app-pricing-gate branch from d2f5ff9 to 8858efa Compare June 5, 2026 15:01
louis030195 pushed a commit that referenced this pull request Jun 5, 2026
scoped to the LLM-reference block only. cross-checked against the codebase,
the brain, and the in-flight pricing launch (website #238 / app #3846):

- pricing: drop removed lifetime/$400/$600/$39; use launch tiers
  Standard $25/mo, Pro $50/seat/mo, Enterprise $150/seat/mo. lifetime
  grandfathered, no new lifetime sales. core engine + CLI stay free/OSS.
- ai search: SQLite FTS5 keyword search, not "semantic embeddings"
  (embeddings exist only for speaker-id; content embeddings are a future TODO)
- built-in pipes: replace nonexistent obsidian-sync/reminders/idea-tracker
  with the actually-shipped pipes (meeting-summary, day-recap, etc.)
- audio: Whisper Large-V3-Turbo locally / Deepgram cloud
- mcp: pin @latest to match the install snippet
- faq + comparison table: one-time/lifetime -> subscription reality

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
louis030195 added a commit that referenced this pull request Jun 5, 2026
scoped to the LLM-reference block only. cross-checked against the codebase,
the brain, and the in-flight pricing launch (website #238 / app #3846):

- pricing: drop removed lifetime/$400/$600/$39; use launch tiers
  Standard $25/mo, Pro $50/seat/mo, Enterprise $150/seat/mo. lifetime
  grandfathered, no new lifetime sales. core engine + CLI stay free/OSS.
- ai search: SQLite FTS5 keyword search, not "semantic embeddings"
  (embeddings exist only for speaker-id; content embeddings are a future TODO)
- built-in pipes: replace nonexistent obsidian-sync/reminders/idea-tracker
  with the actually-shipped pipes (meeting-summary, day-recap, etc.)
- audio: Whisper Large-V3-Turbo locally / Deepgram cloud
- mcp: pin @latest to match the install snippet
- faq + comparison table: one-time/lifetime -> subscription reality

Co-authored-by: Louis Beaumont <louis@screenpi.pe>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Follow-up hardening on the app entitlement gate so it cannot lock out paid
users and cannot silently break the e2e suite.

- offline/stale safety: keep lifetime grants and server-issued grace windows
  valid even when the cached entitlement is stale, in both the Rust native gate
  (store.rs) and the TS gate (lib/app-entitlement.ts). A local-first app must
  not stop recording because it could not reach the server for a few days, and
  a returning paid user must not be locked out after >72h idle.
- auto-resume: when access transitions to entitled mid-session (sign-in,
  purchase, refresh) the gate now restarts capture, since native autostart only
  runs once at launch.
- just-paid race: the gate auto-verifies once against the server with the Stripe
  fallback (verify=true) so a user who just paid unlocks without waiting for the
  webhook; loadUser/use-settings forward the flag.
- security: the native gate only bypasses on debug builds, not a runtime
  TAURI_ENV_DEBUG env var.
- e2e: bypass the gate in e2e builds via NEXT_PUBLIC_SCREENPIPE_E2E (run.sh + CI
  build steps) so the suite keeps exercising real features, plus a localStorage
  override that can only ever force the gate ON for the dedicated gate spec.
- tests: component tests for the gate behaviors and a wdio spec
  (zz-app-entitlement-gate) that asserts the unentitled session is blocked and
  access restores.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@louis030195 louis030195 marked this pull request as ready for review June 5, 2026 18:52
@louis030195 louis030195 merged commit 858aca9 into main Jun 5, 2026
19 of 23 checks passed
louis030195 pushed a commit that referenced this pull request Jun 5, 2026
PR #3846 added the app-entitlement gate, which stops the screenpipe
engine for an unentitled session. The new zz-app-entitlement-gate spec
forces the gate on (dev bypass off, e2e seed is unentitled), so the gate
calls stopScreenpipe and kills the local API sidecar. Clearing the force
flag restores the dev bypass but never restarts the engine: the resume
effect only fires on an isEntitled false->true transition, not a
devBypass one (in production devBypass is a constant env var so this
toggle never happens).

The trailing zz-owned-browser-background-nav spec then fetched the local
API and got "TypeError: fetch failed" (connection refused), failing E2E
on every push across macOS and Windows since 858aca9.

Restart the engine in the gate spec cleanup and wait for the local API
health endpoint, so trailing specs in the shared session find a live API.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
louis030195 pushed a commit that referenced this pull request Jun 5, 2026
The "Generate E2E Coverage Report" step validates that every *.spec.ts in
e2e/specs has an entry in coverage-map.json. Two recently-added specs were
missing entries, so the step failed once the test run itself started
passing:

- privacy-installed-apps.spec.ts (PR #3866)
- zz-app-entitlement-gate.spec.ts (PR #3846)

Add manifest entries for both and regenerate COVERAGE.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.

1 participant