@qwertybit/pr-preview 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -0
- package/LICENSE +30 -0
- package/README.md +242 -0
- package/assets/fonts/Inter.ttf +0 -0
- package/dist/cli/index.js +2251 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/harness/assets/index-BvUCb8Lb.css +1 -0
- package/dist/harness/assets/index-ZmTksMZ5.js +1 -0
- package/dist/harness/index.html +14 -0
- package/dist/harness/logo-wordmark.svg +22 -0
- package/dist/harness/logo.svg +23 -0
- package/dist/inpage/recorder.global.js +344 -0
- package/package.json +83 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project
|
|
5
|
+
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [0.1.0] — 2026-06-08
|
|
8
|
+
|
|
9
|
+
Initial release.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **Record by demonstration**: a headed-Chrome harness loads your app in an
|
|
14
|
+
iframe; every click, keystroke, scroll and navigation becomes an editable
|
|
15
|
+
step with a thumbnail.
|
|
16
|
+
- **Per-pass before/after flow**: record the journey on the PR base branch
|
|
17
|
+
(run in an isolated git worktree) and again on your branch — the two UIs can
|
|
18
|
+
differ completely. A 5-step wizard, tab strip with branch names, and a
|
|
19
|
+
pinned action bar guide each stage.
|
|
20
|
+
- **High-quality output**: produces small, sharp `before.mp4` / `after.mp4`
|
|
21
|
+
via ffmpeg (H.264, near-Full-HD), with an automatic GIF fallback when ffmpeg
|
|
22
|
+
is absent. `format: "mp4" | "gif" | "both"`.
|
|
23
|
+
- **Burned-in captions**: each clip shows its branch, the base it's compared
|
|
24
|
+
against, and a timestamp.
|
|
25
|
+
- **Resilient replay**: a synthetic cursor, human pacing, a ready-page gate,
|
|
26
|
+
a manual-auth popup (passwords are never stored), and selector-drift
|
|
27
|
+
recovery (retry / skip / restart the capture).
|
|
28
|
+
- **Cross-origin without a proxy**: the recorder is injected via Playwright's
|
|
29
|
+
`exposeBinding`; only frame-busting headers (`X-Frame-Options`,
|
|
30
|
+
CSP `frame-ancestors`) are stripped.
|
|
31
|
+
- CLI: `pr-preview init`, `pr-preview record`, `pr-preview run`.
|
|
32
|
+
|
|
33
|
+
[0.1.0]: https://github.com/QwertyBit-Ventures/pr-preview/releases/tag/v0.1.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 QwertyBit (vlad@flowpoint.ai)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
Trademarks. The MIT license above applies to the source code of this CLI only.
|
|
26
|
+
It does NOT grant any rights to the "pr-preview" / "PR Preview" names, the logo,
|
|
27
|
+
or other QwertyBit brand features, which remain trademarks of QwertyBit. The
|
|
28
|
+
hosted pr-preview service (pr-preview.com) and any commercial editions or
|
|
29
|
+
premium add-ons are separate, proprietary offerings and are not covered by this
|
|
30
|
+
license.
|
package/README.md
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/QwertyBit-Ventures/pr-preview/main/npm_package/harness/public/logo-wordmark.svg" alt="PR Preview" width="280" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<strong>See what your PR changed — before & after, in a clip.</strong><br/>
|
|
7
|
+
A free, open-source CLI that records a journey through your app and turns it into a polished
|
|
8
|
+
before/after video for your pull request.
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://www.npmjs.com/package/@qwertybit/pr-preview"><img src="https://img.shields.io/npm/v/@qwertybit/pr-preview?color=635bff" alt="npm version" /></a>
|
|
13
|
+
<a href="./LICENSE"><img src="https://img.shields.io/npm/l/@qwertybit/pr-preview?color=2da44e" alt="MIT license" /></a>
|
|
14
|
+
<img src="https://img.shields.io/node/v/@qwertybit/pr-preview" alt="node >= 20" />
|
|
15
|
+
<a href="https://pr-preview.com"><img src="https://img.shields.io/badge/website-pr--preview.com-635bff" alt="pr-preview.com" /></a>
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
<p align="center">
|
|
19
|
+
<img src="https://raw.githubusercontent.com/QwertyBit-Ventures/pr-preview/main/npm_package/docs/media/demo.gif" alt="PR Preview demo — recording a UI journey and producing a before/after video" width="720" />
|
|
20
|
+
</p>
|
|
21
|
+
|
|
22
|
+
**PR Preview** opens your app in a controlled Chrome window and records the journey you perform —
|
|
23
|
+
clicking through a feature, logging in, submitting a form. The recording *is* the clip (no replay,
|
|
24
|
+
no flaky re-enactment), so what you did is exactly what reviewers see. Do it on your PR's base
|
|
25
|
+
branch and on your branch and you get two high-quality videos you can drag straight into a GitHub
|
|
26
|
+
pull request:
|
|
27
|
+
|
|
28
|
+
| `before.mp4` | `after.mp4` |
|
|
29
|
+
| --- | --- |
|
|
30
|
+
| your journey on the base branch | the same journey, with your changes |
|
|
31
|
+
|
|
32
|
+
No CI to set up, no scripts to write. It runs locally, against your real dev server, and ships in
|
|
33
|
+
about a minute.
|
|
34
|
+
|
|
35
|
+
> **Why it matters:** in the AI era, more of every diff is machine-generated, and reviewers
|
|
36
|
+
> can't infer how the UI behaves from reading generated code. A 15-second before/after clip makes
|
|
37
|
+
> the visual change obvious in seconds — and turns "LGTM" into an actual review.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## ✨ Features
|
|
42
|
+
|
|
43
|
+
- 🎬 **Record by demonstration** — just use your app. Clicks, typing, scrolling and navigation are
|
|
44
|
+
captured as an editable outline; no selectors or scripts to hand-write.
|
|
45
|
+
- 🎥 **Live capture, zero drift** — the clip is your real recording, not a replay, so it never
|
|
46
|
+
desyncs on stateful apps. A synthetic cursor makes every move easy to follow.
|
|
47
|
+
- 🌳 **True before/after** — the base branch runs in an isolated git **worktree**; your working
|
|
48
|
+
tree is never touched. Or point it at an app you already run with `--url`.
|
|
49
|
+
- 🎞️ **Tiny, sharp MP4s** — H.264, near-Full-HD, a few hundred KB. GitHub renders them inline in a
|
|
50
|
+
PR. High-quality GIF fallback when ffmpeg isn't installed.
|
|
51
|
+
- 🔒 **Runs entirely on your machine** — nothing is uploaded. Your source and app data never leave
|
|
52
|
+
your computer.
|
|
53
|
+
- 🏷️ **Self-describing clips** — each is captioned with its branch and a timestamp.
|
|
54
|
+
- 🤖 **Agent-friendly** — config-driven and flag-free, so you can kick it off from Claude Code or CI.
|
|
55
|
+
|
|
56
|
+
## 🚀 Install
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npm i -D @qwertybit/pr-preview
|
|
60
|
+
npx playwright install chromium # one-time browser download
|
|
61
|
+
npx pr-preview init # scaffolds pr-preview.config.js
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
> **ffmpeg** (optional, recommended) gives you MP4 output. macOS: `brew install ffmpeg` ·
|
|
65
|
+
> Debian/Ubuntu: `apt install ffmpeg`. Without it, PR Preview produces a high-quality GIF instead.
|
|
66
|
+
|
|
67
|
+
## ⚡ Quick start
|
|
68
|
+
|
|
69
|
+
On your PR branch:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npx pr-preview run
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
That's it. PR Preview will:
|
|
76
|
+
|
|
77
|
+
1. Detect your PR base, check it out into a worktree, and start its dev server.
|
|
78
|
+
2. Open Chrome with the recording harness. **Record** your journey → **Confirm** → `before.mp4`.
|
|
79
|
+
3. Switch to your branch's app, record the same journey (or reuse the BEFORE outline) → **Save** →
|
|
80
|
+
`after.mp4`.
|
|
81
|
+
4. Open the output folder.
|
|
82
|
+
|
|
83
|
+
Both clips land in `.pr-preview/output/`. Drag them into your PR description — done.
|
|
84
|
+
|
|
85
|
+
Just need one clip (a demo, a bug repro)? `npx pr-preview run --single` records a single standalone
|
|
86
|
+
video, no comparison.
|
|
87
|
+
|
|
88
|
+
## 🧠 How it works
|
|
89
|
+
|
|
90
|
+
A run is a short wizard shown in the harness sidebar:
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
①────────②────────③────────④────────⑤
|
|
94
|
+
Record Capture Record Capture Generate
|
|
95
|
+
(base) before (branch) after files
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
- **The clip is the recording.** Frames are captured live as you perform the journey, then trimmed
|
|
99
|
+
at the ends and captioned — so it looks polished without the drift of re-enacting steps.
|
|
100
|
+
- **Before and after are recorded separately** (a PR can change the UI completely). If the flows
|
|
101
|
+
match, a **Load BEFORE steps** shortcut reuses the outline as a checklist.
|
|
102
|
+
- **Reset nudge** at the start of each pass lets you clear cookies/storage for a clean start, or
|
|
103
|
+
keep a session you set up by hand (e.g. a manual login) — only shown when there's state to reset.
|
|
104
|
+
- **Refresh button** in the frame corner reloads the app whenever you need a clean slate.
|
|
105
|
+
|
|
106
|
+
## 📦 Output
|
|
107
|
+
|
|
108
|
+
| `format` | Result | Needs ffmpeg |
|
|
109
|
+
| --- | --- | --- |
|
|
110
|
+
| `"mp4"` *(default)* | `before.mp4`, `after.mp4` | yes (falls back to GIF) |
|
|
111
|
+
| `"gif"` | `before.gif`, `after.gif` | no |
|
|
112
|
+
| `"both"` | both pairs | yes |
|
|
113
|
+
|
|
114
|
+
MP4 is recommended: full color, far smaller than GIF, and GitHub embeds it inline.
|
|
115
|
+
|
|
116
|
+
## ⚙️ Configuration
|
|
117
|
+
|
|
118
|
+
Everything lives in `pr-preview.config.js` (or `.ts` / `.json`), so a project is set up once and
|
|
119
|
+
runs with **no flags**:
|
|
120
|
+
|
|
121
|
+
```js
|
|
122
|
+
/** @type {import('@qwertybit/pr-preview').Config} */
|
|
123
|
+
export default {
|
|
124
|
+
devCommand: "npm run dev", // required — $PORT is provided
|
|
125
|
+
url: "http://localhost:{port}", // required — {port} is templated in
|
|
126
|
+
cwd: ".", // frontend dir (for monorepos)
|
|
127
|
+
readyTimeout: 60000, // ms to wait for the dev server
|
|
128
|
+
|
|
129
|
+
// Run options (set once here instead of passing CLI flags each time):
|
|
130
|
+
externalUrl: undefined, // use an app you already run (skip the dev server)
|
|
131
|
+
baseBranch: undefined, // override base ("before") detection
|
|
132
|
+
keepWorktree: false, // reuse the base worktree across runs
|
|
133
|
+
|
|
134
|
+
output: ".pr-preview/output",
|
|
135
|
+
format: "mp4", // "mp4" | "gif" | "both"
|
|
136
|
+
passes: 2, // 2 = before/after · 1 = single clip
|
|
137
|
+
resetStorage: true, // default for the start-of-pass reset choice
|
|
138
|
+
viewport: { width: 1920, height: 1080 },
|
|
139
|
+
headerStrip: true, // strip X-Frame-Options / frame-ancestors so the app frames
|
|
140
|
+
|
|
141
|
+
// Browser permissions granted up front so a native prompt never blocks the run:
|
|
142
|
+
permissions: ["geolocation", "clipboard-read", "clipboard-write"], // allow-all by default
|
|
143
|
+
geolocation: undefined, // { latitude, longitude } — fixed & deterministic
|
|
144
|
+
};
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
| Field | Default | Notes |
|
|
148
|
+
| --- | --- | --- |
|
|
149
|
+
| `devCommand` | — | Command that starts your dev server. `$PORT` is set for you. |
|
|
150
|
+
| `url` | — | Where the app answers once ready. `{port}` is replaced. |
|
|
151
|
+
| `cwd` | `"."` | Frontend directory relative to the repo root. |
|
|
152
|
+
| `readyTimeout` | `60000` | How long to wait for `url` to respond. |
|
|
153
|
+
| `externalUrl` | — | Use an app you already run instead of a managed dev server. Same as `run --url`. |
|
|
154
|
+
| `baseBranch` | auto | Override PR-base detection. Same as `run --base`. |
|
|
155
|
+
| `keepWorktree` | `false` | Reuse the base worktree across runs. Same as `run --keep-worktree`. |
|
|
156
|
+
| `format` | `"mp4"` | `mp4` \| `gif` \| `both`. |
|
|
157
|
+
| `passes` | `2` | `2` = before/after comparison; `1` = single standalone clip. `run --single` forces 1. |
|
|
158
|
+
| `resetStorage` | `true` | Default for the start-of-pass reset choice (clear cookies/storage vs. keep your session). |
|
|
159
|
+
| `viewport` | `1920×1080` | Logical app resolution; the window scales to fit. |
|
|
160
|
+
| `headerStrip` | `true` | Strip only frame-busting headers so the app loads in the iframe. |
|
|
161
|
+
| `permissions` | allow-all | Browser permissions to grant (Playwright names). Unlisted ones stay denied — no native prompt blocks the run. |
|
|
162
|
+
| `geolocation` | — | Fixed `{ latitude, longitude }` so location apps render identical results in both clips. |
|
|
163
|
+
|
|
164
|
+
## 🖥️ CLI
|
|
165
|
+
|
|
166
|
+
| Command | What it does |
|
|
167
|
+
| --- | --- |
|
|
168
|
+
| `pr-preview init` | Scaffold `pr-preview.config.js` and a `.gitignore` entry. |
|
|
169
|
+
| `pr-preview record` | Record a journey on the current branch only (`-o <file>`). |
|
|
170
|
+
| `pr-preview run` | The full before/after flow. |
|
|
171
|
+
|
|
172
|
+
`run` flags: `-b, --base <ref>` (override base) · `--keep-worktree` (reuse the base worktree) ·
|
|
173
|
+
`-u, --url <url>` (use your own running app) · `-s, --single` (one standalone clip, no comparison).
|
|
174
|
+
|
|
175
|
+
### Bring your own running app (`--url`)
|
|
176
|
+
|
|
177
|
+
For apps that can't boot in a throwaway checkout (need `.env`, a backend, a database), run the app
|
|
178
|
+
yourself and point PR Preview at it:
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
npm run dev # → http://localhost:3000 (base branch)
|
|
182
|
+
npx pr-preview run --url http://localhost:3000
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
It records BEFORE on your running app, then **pauses** — you switch branches, restart on the same
|
|
186
|
+
URL, and click **Continue** — then it records AFTER. No worktree, no managed dev server.
|
|
187
|
+
|
|
188
|
+
## 🤖 Use it from Claude Code
|
|
189
|
+
|
|
190
|
+
Because every setting lives in the config, a run takes no flags — so an AI agent can kick it off.
|
|
191
|
+
Ask Claude Code for a preview and it runs `npx pr-preview run`; a Chrome window opens, **you click
|
|
192
|
+
through the ~30-second journey**, and the agent picks up the finished `before.mp4` / `after.mp4` to
|
|
193
|
+
drop into your PR. The agent triggers and finalizes; you demonstrate the journey.
|
|
194
|
+
|
|
195
|
+
## 🔐 Privacy
|
|
196
|
+
|
|
197
|
+
PR Preview runs locally — it opens your app in a Chrome window, records, and writes video files to
|
|
198
|
+
your project. Nothing is uploaded. The clip is a real screen recording, so avoid typing real
|
|
199
|
+
production secrets on camera (use a test login, or your own redaction).
|
|
200
|
+
|
|
201
|
+
## Requirements
|
|
202
|
+
|
|
203
|
+
- **Node.js ≥ 20**
|
|
204
|
+
- **Chromium** via Playwright (`npx playwright install chromium`)
|
|
205
|
+
- **ffmpeg** (optional) for MP4 output
|
|
206
|
+
|
|
207
|
+
## Limitations
|
|
208
|
+
|
|
209
|
+
PR Preview drives a real app inside a controlled browser, so a few things are out of scope:
|
|
210
|
+
|
|
211
|
+
- **In-iframe SSO** (e.g. a redirect-style "Sign in with Google") — providers refuse to be framed.
|
|
212
|
+
Log in by hand before recording and keep the session; popup-based OAuth usually works.
|
|
213
|
+
- **CAPTCHA** — complete it by hand.
|
|
214
|
+
- **Canvas/WebGL, closed shadow roots, nested third-party iframes** (Stripe Elements, embedded
|
|
215
|
+
checkout) — limited support.
|
|
216
|
+
|
|
217
|
+
## Contributing
|
|
218
|
+
|
|
219
|
+
See [CONTRIBUTING.md](./CONTRIBUTING.md). Issues and PRs welcome — and a ⭐ helps a lot.
|
|
220
|
+
|
|
221
|
+
## License & what's free
|
|
222
|
+
|
|
223
|
+
The **CLI is open source under the [MIT license](./LICENSE)** — free to use, including commercially.
|
|
224
|
+
This is an open-core project:
|
|
225
|
+
|
|
226
|
+
- ✅ **This CLI** — recording and before/after clip generation. MIT, free forever. Clips carry a
|
|
227
|
+
small `pr-preview.com` watermark.
|
|
228
|
+
- 🔒 **PR Preview for Teams** ([pr-preview.com](https://pr-preview.com)) — the hosted service:
|
|
229
|
+
clip hosting, a synced review player, team reviewers & comments, sharing, and watermark-free
|
|
230
|
+
clips. A separate, proprietary commercial offering — *coming soon*.
|
|
231
|
+
- ™️ The **"PR Preview" name and logo** are trademarks of SC QWERTYBIT SRL; the MIT license covers
|
|
232
|
+
the code, not the brand.
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
<p align="center">
|
|
237
|
+
<a href="https://pr-preview.com"><strong>🎬 pr-preview.com</strong></a><br/>
|
|
238
|
+
<sub>See it in action, and <a href="https://pr-preview.com/#teams">join the early-access list for PR Preview for Teams</a> —<br/>
|
|
239
|
+
hosted clips, team reviews & sharing, coming soon.</sub>
|
|
240
|
+
</p>
|
|
241
|
+
|
|
242
|
+
<p align="center"><sub>Built by <a href="https://pr-preview.com">QwertyBit</a> · Free & Open Source · MIT</sub></p>
|
|
Binary file
|