Gate workspace ZIP exports and refinery dataset downloads behind Workflow Pro - #1802
Gate workspace ZIP exports and refinery dataset downloads behind Workflow Pro#1802groupthinking with Copilot wants to merge 3 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Co-authored-by: groupthinking <154503486+groupthinking@users.noreply.github.com>
…a 402-with-`checkoutUrl` is silently swallowed, so users get no feedback when a download fails.
This commit fixes the issue reported at apps/web/src/components/dashboard/panels.tsx:255
## Bug
`downloadScaffoldPackage` (in `apps/web/src/lib/action-surface.ts`) was changed from an always-succeeding client-side zip into an async network call (`POST /api/workspace/export`). Its `ScaffoldDownloadResult` type has many failure shapes:
- network error → `{ ok: false, status: 0, error }`
- transient 5xx after 3 retries → `{ ok: false, status: 5xx, error }`
- a `500 payment_gate_failed` → `{ ok: false, status: 500, error }`
- a 402 with a null/absent `checkoutUrl` → `{ ok: false, status: 402, checkoutUrl: undefined }`
But the `ActionsPanel` handler only reacted to a single shape:
```ts
const result = await downloadScaffoldPackage(pkg);
if (!result.ok && result.checkoutUrl) {
window.location.href = result.checkoutUrl;
}
```
**Concrete trigger:** a Pro user (or any user hitting a transient 500 / network error) clicks "Export package". `result.ok` is `false` and `result.checkoutUrl` is `undefined`, so the `if` branch is skipped and nothing happens — no download, no error, no feedback. This is a regression in error visibility because the previous implementation always produced a zip locally.
The sibling handler in `OneLoopStudio.tsx` handles all three cases (402+url redirect, other-failure toast, success toast) via `setExportToast`, confirming an established pattern for surfacing export outcomes.
## Fix
`ActionsPanel` had no error/success UI mechanism, so I added a lightweight one mirroring the `OneLoopStudio` pattern:
- Added `exportMessage` state (`{ tone: 'success' | 'error'; text }`) with an auto-dismiss `useEffect` (5s).
- Rewrote `exportScaffold` to handle every result shape: `402 + checkoutUrl` → error toast + redirect; any other failure → error message with `result.error`; success → success message with the filename; plus a `try/catch` for thrown errors.
- Rendered the message inside the "Project scaffold" section with `role="alert"`/`role="status"` for accessibility.
Type-checking `panels.tsx` with `tsc --noEmit` reports no errors.
Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
Co-authored-by: groupthinking <garveyht@gmail.com>
|
Important Review skippedBot user detected. To trigger a single review, invoke the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Advanced Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Snapshot WarningsEnsure that dependencies are being submitted on PR branches and consider enabling retry-on-snapshot-warnings. See the documentation for more information and troubleshooting advice. Scanned FilesNone |
| const trimmedPath = path.trim().replace(/\\/g, '/'); | ||
| if (!trimmedPath || trimmedPath.startsWith('/')) return null; | ||
| if (trimmedPath.split('/').some((part) => !part || part === '.' || part === '..')) return null; | ||
| normalized[trimmedPath] = content; |
🔍 PR Validation
|
|
Backlog triage: leaving open. Workflow Pro ZIP/dataset gate (#1643) is real but CONFLICTING vs rewritten |
|
CoS hold: named timeout cut in flight. Diff includes |
Canonical issue
Linked by the system.
Outcome
Workspace ZIP exports and
/api/v1/refinery/datasetnow fail closed for free callers with a Stripe-backed402response, while paid callers can unlock access immediately via verified checkout session activation and retry the same download flow without losing context.Scope
apps/web/src/lib/billing/pro-feature-gate.ts.POST /api/workspace/export.402 payment_requiredwith Stripe checkout metadata for free callers.GET /api/v1/refinery/dataset.402responses.workspaceZipExportandrefineryDatasetAccess.Risk
Verification
List exact automated and manual checks, tied to the current head SHA.
npm test --prefix apps/web -- src/lib/__tests__/action-surface.test.ts src/app/api/__tests__/workspace-export-route.test.ts src/app/api/v1/refinery/dataset/__tests__/route.test.ts src/app/api/__tests__/billing-activate-route.test.ts src/app/api/__tests__/billing-checkout-route.test.ts src/app/api/__tests__/billing-renew-route.test.ts src/app/api/__tests__/billing-spoofing.test.ts src/app/api/__tests__/video-generate-route.test.ts src/app/api/__tests__/actions-route.test.tsProduction evidence
Agent handoff