Repository navigation
feat(studio): share review pages from local preview - #7140
Conversation
e772bed to
9c106b8
Compare
af04e02 to
4248185
Compare
9c106b8 to
0b3b185
Compare
1924aee to
9a627dc
Compare
0b3b185 to
570d844
Compare
9a627dc to
02aa315
Compare
570d844 to
93d025d
Compare
02aa315 to
3e5c5b4
Compare
93d025d to
734e2f3
Compare
3e5c5b4 to
09c567a
Compare
734e2f3 to
154d9a8
Compare
09c567a to
3a74738
Compare
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
jrusso1020
left a comment
There was a problem hiding this comment.
Reviewed at 3a74738fc76440cdfafda11f5b00f08dfa9f8518, scoped to the 24-file increment over #7135 at f78dca1bfd559d3b8076d2554d51c3cc03d61d7d (verified ancestor; tree-identical to the previously reviewed #7138 head 154d9a8eb1ca9d9cf2e41b6fa1f48a21412dbd0c).
No blocking findings. The bridge fixes the project directory server-side, requires same-origin loopback browser metadata plus a per-panel token, pins the service to owner/backend identity, rechecks that identity for job visibility, and repeats the busy guard after asynchronous identity verification (shareRoutes.ts, shareSessions.ts, share/auth.ts). The UI drains the existing editor-save queue before sharing; a rejected drain stops the action before its POST (traced through usePreviewPersistence.waitForPendingDomEditSaves and covered by the UI failure test). It aborts requests and clears polling on close, and clears account-specific controls when a request fails. Portable freshness remains unknown unless evidence establishes a change; it never labels matching video bytes as proof of matching source inputs.
Audited: new sharing bridge, presenters/freshness/session helpers, shared DTO, auth/service changes, QuickShare controls/client/hook/telemetry, docs and new tests.
Integration scope: App, StudioHeader, studioServer and studio-server index wiring; existing rendering, save-queue, upload/source and telemetry internals traced at their consumer boundaries rather than re-audited in full.
Validation at this head: full bun run build passed; Node 22 vitest run src/share src/commands/share.test.ts src/server/shareRoutes.test.ts src/server/shareFreshness.test.ts in packages/cli passed 76 tests across 9 files; vitest run src/components/share in packages/studio passed 15 tests across 2 files. Bridge tests invoke the Hono routes with fake services; UI tests use happy-dom and mocked controls/network, not authenticated uploads. Independently adversarially traced account changes, concurrent actions, recovery and browser boundaries. Inspected all four refreshed light/dark captures; they show the entry point and signed-out recovery only. No live signed-in upload, quota exhaustion, recipient source delivery or cross-client acceptance exercised. Local project scripts remain trusted as documented.
Nit: QuickShareControls.tsx:176 derives the last-upload files indicator from the latest job result, so an access/off/on/login job replaces it with not_checked. Consider retaining upload provenance separately if that indicator should survive management actions. This loses explanatory status, not source data or access controls.
Need: yes · Size: ok, cohesive Studio integration · Reuse: CLI sharing service/kernel, editor-save drain, existing UI and telemetry controls · Simpler: already focused · Structure: fine
Risk: medium — new authenticated local bridge and asynchronous UI; identity/origin guards are explicit, with live acceptance still unverified.
— hf-review
Verdict: APPROVE
Reasoning: The integration preserves explicit audience consent and account boundaries, guards overlapping bridge actions, and avoids claiming unproved content freshness. No concrete blocker found in the reviewed increment.
jrusso1020
left a comment
There was a problem hiding this comment.
Reviewed at be7b5f7d1d1b1cda44e39382f9cb2f82724a1708. Delta review of eight files since the prior approval at 3a74738fc; base #7135 remains f78dca1bfd559d3b8076d2554d51c3cc03d61d7d, verified ancestor.
No new blocking findings. packages/cli/src/share/errors.ts:33 maps review-service HTTP 401 to the existing login_expired recovery code; 403 admission reasons remain distinct. Traced both snapshot and failed-job consumers to the existing explicit browser-login control and service reset. The closure-based running-job checks preserve both guards, including the second check after awaiting identity verification. Workflow filters now include sharing dependencies, and the smoke bootstrap fixture supplies the client’s required token shape.
Audited the eight-file delta, full bridge/classifier and UI recovery consumers; the remainder of the original Studio-sharing increment retains the prior review’s scope and limitations. Inspected the supplied expired-session before/after images: the latter displays browser sign-in recovery. These images do not establish successful login or authenticated sharing. No live login/upload, recipient delivery or cross-client acceptance performed. The previous upload-provenance display Nit remains a follow-up.
Validation: full bun run build and CLI tsc --noEmit passed. Node 22 vitest run src/share src/commands/share.test.ts src/server/shareRoutes.test.ts src/server/shareFreshness.test.ts passed 80 tests / 9 files; Studio vitest run src/components/share passed 16 tests / 2 files; node --test scripts/studio-runtime-smoke.test.mjs passed 7 tests. Restoring only the old classifier makes all three new 401 regressions fail (23 other route tests pass); restoring this head passes all 26 route tests. Bridge tests use fake services and UI tests use mocked fetch/controls. Independent adversarial delta pass found no blocker.
Need: yes · Size: ok, focused follow-up · Reuse: existing shareError classifier and ShareLogin recovery · Simpler: already minimal · Structure: fine
Risk: medium — authenticated local bridge; this delta is limited to recovery classification and the accompanying typing, fixture and CI changes.
— hf-review
Verdict: APPROVE
Reasoning: Expired sessions expose the existing explicit login action while admission failures and concurrent-action guards retain their behavior. No introduced blocker found in this follow-up.
jrusso1020
left a comment
There was a problem hiding this comment.
Reviewed at dbb85bfd7c03bab3ee076bd90570c53464c2b737. Four-file delta since the prior approval at be7b5f7d1; #7135 base remains f78dca1bfd559d3b8076d2554d51c3cc03d61d7d, verified ancestor.
No new blocking findings. useQuickShare.ts:88 reconnects an idle failed panel on focus/visible return. The synchronous working ref prevents two return events from starting overlapping automatic refreshes and guards run() against an action starting during that read; successful snapshots disarm reconnection, so healthy focus changes preserve selections. Both listeners are removed alongside request/timer cleanup. Login completion still uses the existing job-poll → fresh snapshot path; no return handler starts login, upload or share creation.
Audited the complete hook, controls/client and lifecycle consumers, four-file delta and tests/docs. The remainder retains the prior review’s scope. The original upload-provenance display Nit remains a follow-up. Inspected the explicitly fixture-backed browser image: workspace controls appear with audience unset and Create disabled; this does not establish live OAuth or authenticated upload. No live sign-in, upload, source delivery or cross-client acceptance performed.
Validation: Node 22 vitest run src/components/share passed 20 tests / 2 files; with two independent return-event scenarios, 22 passed (paired focus/visibility admits one read; hidden return defers recovery). Restoring the old hook fails the two new error-return regressions (2 failed, 18 passed). Studio tsc --noEmit passed. Full workspace bun run build and an explicit restored-source Studio build both passed. Tests exercise mounted UI with mocked network/controls. Fresh independent adversarial delta review completed.
Need: yes · Size: ok, focused reconnection follow-up · Reuse: existing refresh/poll and auth recovery · Simpler: already focused · Structure: fine
Risk: medium — adds browser lifecycle retries to an authenticated sharing panel.
— hf-review
Verdict: APPROVE
Reasoning: Failure recovery reconnects without resetting healthy choices or automatically publishing, and listener cleanup is paired with mount. No introduced blocker found in this delta.
Advertise the CLI sharing bridge before bootstrapping it so standalone Studio does not request unsupported routes. Preserve origin and session checks. Budget the intended sharing artifact: clean main packs at 8,060,519 bytes versus 8,162,979 with sharing (8,169,168 in CI). Required policy and Unicode tables, bundled sharing code, and Studio controls account for the growth. Set the packed-only budget to 8,577,627, following the 5% headroom convention; retain the unpacked cap and all package checks.
Advertise the CLI sharing bridge before bootstrapping it so standalone Studio does not request unsupported routes. Preserve origin and session checks. Budget the intended sharing artifact: clean main packs at 8,060,519 bytes versus 8,162,979 with sharing (8,169,168 in CI). Required policy and Unicode tables, bundled sharing code, and Studio controls account for the growth. Set the packed-only budget to 8,577,627, following the 5% headroom convention; retain the unpacked cap and all package checks.
Advertise the CLI sharing bridge before bootstrapping it so standalone Studio does not request unsupported routes. Preserve origin and session checks. Budget the intended sharing artifact: clean main packs at 8,060,519 bytes versus 8,162,979 with sharing (8,169,168 in CI). Required policy and Unicode tables, bundled sharing code, and Studio controls account for the growth. Set the packed-only budget to 8,577,627, following the 5% headroom convention; retain the unpacked cap and all package checks.
Advertise the CLI sharing bridge before bootstrapping it so standalone Studio does not request unsupported routes. Preserve origin and session checks. Budget the intended sharing artifact: clean main packs at 8,060,519 bytes versus 8,162,979 with sharing (8,169,168 in CI). Required policy and Unicode tables, bundled sharing code, and Studio controls account for the growth. Set the packed-only budget to 8,577,627, following the 5% headroom convention; retain the unpacked cap and all package checks.
…7135) * feat(cli): share rendered videos through unified reviews (heygen-com#7135) * feat(share): attach editable project sources to reviews (heygen-com#7137) * feat(share): measure local sharing outcomes (heygen-com#7138) * feat(cli): stage the sixty-day publish transition (heygen-com#7136) * feat(studio): share review pages from local preview (heygen-com#7140) Advertise the CLI sharing bridge before bootstrapping it so standalone Studio does not request unsupported routes. Preserve origin and session checks. Budget the intended sharing artifact: clean main packs at 8,060,519 bytes versus 8,162,979 with sharing (8,169,168 in CI). Required policy and Unicode tables, bundled sharing code, and Studio controls account for the growth. Set the packed-only budget to 8,577,627, following the 5% headroom convention; retain the unpacked cap and all package checks. * fix(share): persist refusals and improve CLI retry feedback * fix(ci): restore render diagnostics and include sharing workspace * fix(cli): keep sharing owner error codes stable * fix(share): clarify update feedback and align audience changes * fix(share): clarify updates and avoid scratch-file rerenders * fix(cli): report active shares and preserve update channels * fix(cli): resolve update channel when checking registry * fix(ci): refresh sharing package budgets after rebase * fix(share): require consent before uploading project files

Add Share beside Export in local Studio: sign in, choose an explicit audience, upload a saved project, copy its review link, and add versions. Source failures offer an explicit video-only retry; closing the panel leaves the server job running.
Restacked onto #7135 after the shared kernel, CLI, source, and telemetry changes merged there. Each panel has a separate request token and account/backend-bound service. Account changes reject stale mutations and job reads; authentication failures clear the old workspace/link controls. Portable input checks use the completed upload checksum and retain unknown freshness when evidence cannot establish which project inputs were uploaded.
Validation: 587 CLI tests (including sharing and agent-mode coverage), 93 sharing-kernel tests, and 37 Studio sharing tests pass. The focused sharing suites were rerun after the final refactor. Full workspace build, typechecks, normal commit hooks/Fallow, and clean packed-consumer checks pass. Local CLI packed-size validation remains slightly over budget, also reproduced on the preceding commit: 8,085,762 bytes before versus 8,082,004 bytes after these fixes. No size budget was changed. Full CI and CodeQL are running on the latest head because this PR targets a non-main branch.
Live signed-in upload, quota exhaustion, recipient source delivery, and cross-client acceptance remain pending. Local preview assumes trusted project scripts; the browser boundary protects against foreign origins.
Refreshed visual evidence
Fresh controlled captures use the same guest Chromium session, 1280×720 viewport, localhost URL, copied repository
studio-openfixture at time 0, and empty isolated credential directory. The before build restores only the base (f78dca1b) App/Header integration; the after build restores this PR’s implementation. Both saved images were inspected. No API interception or UI response fixtures were used. The fixture’s two lint findings are unchanged.These images demonstrate the entry point and signed-out recovery, not authenticated sharing acceptance.
Original captures retained for history (prior head)
Before
Local Studio built from the parent branch. The header has Export and Open in desktop app; no Share entry point.
After
Local Studio built with the Share popover and local bridge. Share opens the sign-in prompt when credentials are absent.
Capture contract: same in-app Chromium session, 1280×720 viewport, same
http://127.0.0.1:3140/URL and copiedstudio-openrepository fixture at time 0. The server was swapped between base and head; no intercepted API responses or UI mocks. An isolated emptyHYPERFRAMES_CONFIG_DIRmakes both runs signed out. The fixture’s two lint findings predate this change. Theme transitions were allowed to settle before the final captures.These captures prove the header/popover and signed-out recovery only. Real signed-in upload, quota exhaustion, source delivery and cross-client acceptance remain open; they are not demonstrated by these images.
Expired-session recovery
Review-service HTTP 401 responses now map to the existing browser sign-in action; HTTP 403 admission failures retain their own error codes. The login flow starts only when the user presses Sign in in browser.
Fresh captures below use the actual expired-session response on the same localhost preview, project, default credential profile, guest browser, and 1280×720 viewport. The server was restarted with the recovery fix between captures. No API responses were intercepted, and no login was initiated for this capture.
Continue automatically after sign-in
Completed browser sign-in reloads sharing state without a Refresh click. Returning to an idle panel after an authentication or polling failure also reconnects automatically; healthy panels retain audience/workspace choices when focus changes. No recovery path creates a share or bypasses audience consent.
The following browser capture uses explicit local API fixtures for running login → completed login → authenticated snapshot. It proves the UI transition and disabled Create action before choosing an audience; it does not prove live OAuth completion or authenticated upload. No authentication or publish request reached the server during this capture.
Sharing control polish
The audience control now uses an icon-led radio menu with descriptions, while the link address, copy action, primary update action, and quiet management controls follow the Desktop sharing hierarchy. New shares still require an explicit audience; the signed-in workspace remains fixed and existing private shares keep their permissions.
Upgrade to Pro appears only when the workspace entitlement explicitly says Free and opens the public pricing page. Subscribed and unknown entitlements do not show it. The captures below use the built UI with a clearly labelled simulated Free entitlement (2 of 5 links); they verify the menu, usage, and pricing CTA, not live billing or checkout. No publishing or account mutation was permitted by the fixture.
Validation: 36 Studio sharing tests, 3 entitlement presentation tests, Studio/CLI builds, typecheck, and normal commit hooks passed.
Failure recovery validation
The CLI pins the signed-in account for the command. Terminal export failures survive process restarts:
share --status --jsonreturnsok: false,state: "failed", and exit 1, with the previous ready link retained inpreviousUrl. Explicit updates retry the export. Corrupt optional failure metadata does not discard pending uploads or the previous ready version.The following additional screenshots use isolated mocked API responses, not live uploads. They show a failed first export with Create share link enabled, and a failed update with the previous shared link preserved. Existing before/after captures above are retained.