sitedrift 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Joe Severino
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.
package/README.md ADDED
@@ -0,0 +1,161 @@
1
+ # sitedrift
2
+
3
+ **Catch the drift between dev and live.** A zero-build, zero-dependency dev tool
4
+ that frames your local site and production **side-by-side on the same route**,
5
+ locked to the same scroll — then overlays them in `difference` mode so the only
6
+ things that light up are the pixels that actually changed.
7
+
8
+ ```
9
+ ┌─────────────── sitedrift ───────────────┐
10
+ │ DEV ▸ /pricing 200 LIVE ▸ /pricing 200 │
11
+ │ ┌───────────┐ │ ┌───────────┐ Overlay ▸ Diff │
12
+ │ │ $19 │ │ │ $29 │ ≠ meta │
13
+ │ │ [Start…] │ │ │ [Get…] │ ✓ author notes │
14
+ │ └───────────┘ │ └───────────┘ │
15
+ └──────────────────────────────────────────┘
16
+ ```
17
+
18
+ ---
19
+
20
+ ## Quick start
21
+
22
+ No install — run it with `npx` (needs Node ≥ 18):
23
+
24
+ ```bash
25
+ npx sitedrift /pricing \
26
+ --dev http://localhost:4321 \
27
+ --live https://example.com \
28
+ --open
29
+ ```
30
+
31
+ That boots the viewer on `http://127.0.0.1:4178`, opens it at `/pricing`, and
32
+ puts your dev build on the left and production on the right. Type any route in
33
+ the toolbar and both panes follow.
34
+
35
+ Install it globally if you reach for it often:
36
+
37
+ ```bash
38
+ npm i -g sitedrift
39
+ sitedrift /pricing -d http://localhost:4321 -l https://example.com -o
40
+ ```
41
+
42
+ ---
43
+
44
+ ## What it does
45
+
46
+ - **One view switch** — Split (divider) · Solo (one pane, Swap flips) · Overlay
47
+ (stacked). In Overlay an opacity slider blends the panes and **Diff**
48
+ (`mix-blend-mode: difference`) lights up only the changed pixels. Overlay
49
+ force-locks scrolling so the panes can't drift. Keys: `O` overlay, `D` diff.
50
+ - **Locked scrolling** with one controller (exact pixel or proportional) — no
51
+ duplicate scrollbars, no bounce. An internal link click mirrors to both panes.
52
+ - **Metadata diff + status** — title / description / canonical compared across
53
+ sides (`≠ meta`), and a per-pane `200/3xx/4xx/5xx/ERR` badge refreshed on every
54
+ route load, so a route that 404s on one side jumps out.
55
+ - **SEO panel** — Google-style snippet preview + a ~13-point checklist per pane
56
+ (title/description length, single H1, canonical, viewport, lang, Open Graph,
57
+ noindex, image alt…), with a flag showing how many checks fail.
58
+ - **Review notes as a shared channel** — author/route/side-tagged notes in a JSON
59
+ file the viewer polls every 4s, so a teammate or an AI coding session can leave
60
+ notes that appear live. Click a note to jump to its route, copy a per-note
61
+ deep link, dock or float the drawer, and **Send to vault** or export Markdown.
62
+ - **No dependencies.** Node standard library only.
63
+
64
+ ### Keyboard
65
+
66
+ | Key | Action |
67
+ |---|---|
68
+ | `O` | Toggle Overlay |
69
+ | `D` | Toggle the Overlay difference blend |
70
+ | `S` | Swap sides |
71
+ | `R` | Reload both panes |
72
+ | `0` | Reset divider to 50/50 |
73
+ | `/` | Focus the route field |
74
+ | `Space` / `⇧Space` | Page down / up (when scrolling is linked) |
75
+ | `↑` `↓` | Line scroll both panes |
76
+ | `Esc` | Close the notes drawer / open popovers |
77
+
78
+ Shortcuts work whether focus is in the viewer chrome or inside either pane.
79
+
80
+ ---
81
+
82
+ ## Options
83
+
84
+ Every option is a CLI flag, and also reads a `SITEDRIFT_<NAME>` env var.
85
+ Precedence is **flag > env > default**.
86
+
87
+ | Flag | Env | Default | Purpose |
88
+ |---|---|---|---|
89
+ | `-d, --dev <url>` | `SITEDRIFT_DEV` | `http://127.0.0.1:4321` | Left-pane (dev) origin. |
90
+ | `-l, --live <url>` | `SITEDRIFT_LIVE` | `https://example.com` | Right-pane (live) origin. |
91
+ | `-p, --port <n>` | `SITEDRIFT_PORT` | `4178` | Listen port. |
92
+ | `--host <addr>` | `SITEDRIFT_HOST` | `127.0.0.1` | Bind address. |
93
+ | `-o, --open` | — | off | Open the viewer in your browser. |
94
+ | `--http` | — | — | Force plain HTTP (ignore `--cert`/`--key`). |
95
+ | `--cert <file>` / `--key <file>` | `SITEDRIFT_CERT` / `_KEY` | — | If both set, serve over HTTPS. |
96
+ | `--notes <file>` | `SITEDRIFT_NOTES` | `$TMPDIR/sitedrift-notes.json` | Shared review-notes file. |
97
+ | `--brand <text>` | `SITEDRIFT_BRAND` | — | Strip `\| <text>` from titles in pane headers. |
98
+ | `--author <name>` | `SITEDRIFT_AUTHOR` | `you` | Byline for notes added in the viewer. |
99
+ | `--vault <dir>` | `SITEDRIFT_VAULT` | — | Enable **Send to vault** (writes the review markdown here). |
100
+
101
+ A positional `[path]` (e.g. `sitedrift /pricing`) sets the initial route.
102
+ `-h, --help` and `-v, --version` do what you'd expect.
103
+
104
+ ### HTTP endpoints
105
+
106
+ | Route | Purpose |
107
+ |---|---|
108
+ | `GET /` | The viewer. |
109
+ | `GET /health` | `{ dev, live, version }`. |
110
+ | `GET /notes` · `POST /notes` | Read / mutate notes (`op: add\|remove\|toggle\|clear`). |
111
+ | `GET /notes.md` | Notes as a Markdown checklist. |
112
+ | `POST /notes/save` | Write the notes markdown into `--vault`. |
113
+ | `GET /icon.svg` | The app mark / favicon. |
114
+ | `GET /__dev/*` · `GET /__live/*` | Proxied origins. |
115
+
116
+ `POST /notes` requires `Content-Type: application/json`, so a cross-origin page
117
+ can't forge a no-preflight write. Add a note from anywhere:
118
+
119
+ ```bash
120
+ curl -X POST localhost:4178/notes -H 'content-type: application/json' \
121
+ -d '{"op":"add","text":"H1 on /about is larger on LIVE",
122
+ "author":"claude","route":"/about","side":"live"}'
123
+ ```
124
+
125
+ Most viewer state (route, layout, scroll mode, focus) is mirrored into the URL
126
+ query string, so a link reproduces the exact view.
127
+
128
+ ---
129
+
130
+ ## Security — local development only
131
+
132
+ The proxy strips `Content-Security-Policy`, `X-Frame-Options`, and the
133
+ Cross-Origin-{Embedder,Opener,Resource}-Policy headers so production can be
134
+ framed next to dev. That is safe **only on loopback**:
135
+
136
+ - It binds to `127.0.0.1` unless you override `--host`. **Do not** bind it to a
137
+ public interface or put it behind a public proxy.
138
+ - Treat the notes file as plaintext shared scratch space.
139
+
140
+ ## Limitations
141
+
142
+ - **URL rewriting is regex-based**, tuned for static sites (e.g. Astro builds).
143
+ It rewrites root-relative `href`/`src`/`srcset`/`url(...)` and Vite/`_astro`
144
+ paths, but won't catch URLs built in JS (`fetch`, dynamic `import`, import
145
+ maps). SPAs with client-side absolute fetches may need extra rules.
146
+ - Designed for two origins of the *same* site, not arbitrary cross-site diffing.
147
+
148
+ ---
149
+
150
+ ## Docs
151
+
152
+ - [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) — internals, invariants, and the
153
+ module map.
154
+
155
+ ## Credits
156
+
157
+ Created by [Joe Severino](https://github.com/joeseverino).
158
+
159
+ ## License
160
+
161
+ [MIT](LICENSE) © 2026 Joe Severino
@@ -0,0 +1 @@
1
+ <svg width="512" height="512" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><rect width="512" height="512" rx="112.64" fill="#71d99e"/><g fill="#ffffff" transform="translate(256 256) scale(0.12348 -0.12348) translate(-1372.92 -745.00)"><path transform="translate(0.00 0)" d="M691.19921875 -24Q491.9996337890625 -24 352.39984130859375 36.300018310546875Q212.800048828125 96.60003662109375 139.80010986328125 212.39999389648438Q66.8001708984375 328.199951171875 66.8001708984375 492.7998046875H417.99761962890625Q420.3975830078125 423.5992431640625 454.49774169921875 373.8988342285156Q488.597900390625 324.19842529296875 549.9982604980469 297.6982116699219Q611.3986206054688 271.197998046875 695.1991577148438 271.197998046875Q769.7996826171875 271.197998046875 825.1000671386719 290.7981872558594Q880.4004516601562 310.39837646484375 911.4006652832031 345.7987365722656Q942.40087890625 381.1990966796875 942.40087890625 428.39959716796875Q942.40087890625 469.59991455078125 915.8008422851562 500.400146484375Q889.2008056640625 531.2003784179688 833.1006774902344 554.1005554199219Q777.0005493164062 577.000732421875 688.2002563476562 595.0008544921875L536.4000244140625 625.6010131835938Q317.9998779296875 669.6011962890625 206.60003662109375 777.2009887695312Q95.2001953125 884.80078125 95.2001953125 1048.0006103515625Q95.2001953125 1187.4004516601562 169.50003051757812 1292.1003112792969Q243.79986572265625 1396.8001708984375 376.599609375 1455.4000854492188Q509.39935302734375 1514 685.1990356445312 1514Q864.9986572265625 1514 995.0984191894531 1455.5000305175781Q1125.1981811523438 1397.0000610351562 1197.1980590820312 1287.400146484375Q1269.1979370117188 1177.8002319335938 1273.9979248046875 1024.400390625H932.8004150390625Q925.6004028320312 1114.8011474609375 860.3999938964844 1166.7015686035156Q795.1995849609375 1218.6019897460938 690.3988647460938 1218.6019897460938Q624.7984008789062 1218.6019897460938 573.8980407714844 1199.0018005371094Q522.9976806640625 1179.401611328125 494.09747314453125 1145.2012634277344Q465.197265625 1111.0009155273438 465.197265625 1065.8004760742188Q465.197265625 1025.4002075195312 489.59735107421875 996.7999877929688Q513.9974365234375 968.1997680664062 566.6976318359375 946.7995910644531Q619.3978271484375 925.3994140625 702.5982055664062 908.7992553710938L832.3988037109375 882.7990112304688Q956.5985717773438 858.198974609375 1046.5984191894531 820.9989624023438Q1136.5982666015625 783.7989501953125 1194.2981872558594 731.3989868164062Q1251.9981079101562 678.9990234375 1279.5980834960938 610.2991027832031Q1307.1980590820312 541.5991821289062 1307.1980590820312 454.79931640625Q1307.1980590820312 304.19964599609375 1234.09814453125 196.99978637695312Q1160.9982299804688 89.7999267578125 1023.0984802246094 32.89996337890625Q885.19873046875 -24 691.19921875 -24Z"/><path transform="translate(1281.84 0)" d="M651.1993408203125 0H253.199951171875V307.19775390625H632.7994384765625Q767.4002075195312 307.19775390625 854.000732421875 356.1980895996094Q940.6012573242188 405.19842529296875 982.9015197753906 502.7989501953125Q1025.2017822265625 600.3994750976562 1025.2017822265625 744.800048828125Q1025.2017822265625 890.4005737304688 982.3015441894531 987.7010803222656Q939.4013061523438 1085.0015869140625 851.2008666992188 1133.9019165039062Q763.0004272460938 1182.80224609375 627.1998291015625 1182.80224609375H246.7999267578125V1490H650.399658203125Q877.7994995117188 1490 1045.6993103027344 1398.6000366210938Q1213.59912109375 1307.2000732421875 1305.3989868164062 1139.9000854492188Q1397.1988525390625 972.60009765625 1397.1988525390625 744.800048828125Q1397.1988525390625 517.3999633789062 1305.9989624023438 350.2999572753906Q1214.799072265625 183.199951171875 1047.6991882324219 91.5999755859375Q880.5993041992188 0 651.1993408203125 0ZM462.39794921875 1490V0H93.600830078125V1490Z"/></g></svg>
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "sitedrift",
3
+ "version": "0.1.0",
4
+ "description": "Catch the drift between dev and live — frame your local site and production side-by-side on the same route, locked scroll, with a difference-blend overlay. Zero dependencies.",
5
+ "type": "module",
6
+ "bin": {
7
+ "sitedrift": "sitedrift.mjs"
8
+ },
9
+ "files": [
10
+ "sitedrift.mjs",
11
+ "assets/icon.svg",
12
+ "README.md",
13
+ "LICENSE"
14
+ ],
15
+ "engines": {
16
+ "node": ">=18"
17
+ },
18
+ "scripts": {
19
+ "start": "node sitedrift.mjs",
20
+ "test": "node --check sitedrift.mjs"
21
+ },
22
+ "publishConfig": {
23
+ "access": "public"
24
+ },
25
+ "keywords": [
26
+ "dev-tool",
27
+ "visual-diff",
28
+ "visual-regression",
29
+ "staging",
30
+ "production",
31
+ "side-by-side",
32
+ "proxy",
33
+ "seo",
34
+ "astro",
35
+ "overlay"
36
+ ],
37
+ "author": "Joe Severino (https://github.com/joeseverino)",
38
+ "license": "MIT",
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "git+https://github.com/joeseverino/sitedrift.git"
42
+ },
43
+ "homepage": "https://github.com/joeseverino/sitedrift#readme",
44
+ "bugs": {
45
+ "url": "https://github.com/joeseverino/sitedrift/issues"
46
+ }
47
+ }