@voila.dev/cliche 0.1.10 → 0.1.12

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/README.md CHANGED
@@ -1,69 +1,35 @@
1
- <img src="assets/og.png" alt="cliche un cliché of every page. Front-end PRs you can SEE, and a photo album of your app by accident." width="100%">
1
+ <img src="https://raw.githubusercontent.com/voila-voila-dev/cliche/main/assets/og.png" alt="cliche: screenshot any page, get a URL. Just Bun." width="100%">
2
2
 
3
3
  # cliche 📸
4
4
 
5
- **Take a _cliché_ of any page and get a shareable URL.** No Playwright, no
6
- browser download, no dependencies just Bun. Ouistiti ! 🐒
5
+ Screenshot any page, get a URL. No Playwright, no browser download, no
6
+ dependencies. Just Bun. Ouistiti ! 🐒
7
7
 
8
- > _Un cliché_ is French for a snapshot. This one screenshots your app with
9
- > [`Bun.WebView`](https://bun.com/docs/runtime/webview), uploads it to any
10
- > S3-compatible bucket with `Bun.S3Client`, and hands you the URL (or the
11
- > markdown line) to paste into a pull request. **Everything runs on your
12
- > machine** — the only thing that leaves it is the upload to *your* bucket.
13
- >
14
- > This very image was captured by cliche, from an HTML file, in one command.
15
- > [cliche.voila.dev](https://cliche.voila.dev)
8
+ Capture runs on [`Bun.WebView`](https://bun.com/docs/runtime/webview), upload
9
+ on `Bun.S3Client`. Everything happens on your machine; the only thing that
10
+ leaves it is the upload to your own bucket. Requires Bun 1.4.0 or newer.
11
+
12
+ [cliche.voila.dev](https://cliche.voila.dev)
16
13
 
17
14
  ```sh
18
- bunx @voila.dev/cliche https://localhost:4001/missions mission-list.png --upload --prefix pr-123
15
+ bunx @voila.dev/cliche http://localhost:3000/missions shot.png --upload --prefix pr-123
19
16
  ```
20
17
 
21
18
  ```
22
- Captured https://localhost:4001/missions -> mission-list.png
23
- Uploaded mission-list.png -> pr-123/2026-08-29-mission-list-d1cf773c.png
24
- https://assets.example.com/pr-123/2026-08-29-mission-list-d1cf773c.png
19
+ Captured http://localhost:3000/missions -> shot.png
20
+ Uploaded shot.png -> pr-123/2026-08-29-shot-d1cf773c.png
21
+ https://assets.example.com/pr-123/2026-08-29-shot-d1cf773c.png
25
22
  ```
26
23
 
27
- The URL is yours to paste anywhere; add `--markdown` to get a ready-made
28
- `![mission list](…)` line for `gh pr edit --body` instead.
24
+ Paste the URL anywhere, or add `--markdown` for an `![shot](…)` line.
29
25
 
30
- Or skip the CLI entirely and give the tools to your agent — `cliche` is also
31
- a local MCP server:
26
+ ## Why
32
27
 
33
- ```sh
34
- claude mcp add cliche -- bunx @voila.dev/cliche mcp
35
- ```
28
+ A diff shows the code. A screenshot shows what the user gets. Put both in the
29
+ PR and review stops being guesswork.
36
30
 
37
- ## Why you want this
38
-
39
- **1. Front-end PRs you can SEE.** A diff tells the reviewer what changed in
40
- the code; a before/after tells them what changed *for the user*. When every
41
- UI pull request ships with its pixels, review gets faster, regressions get
42
- caught at a glance, and "looks good to me" actually means someone looked.
43
-
44
- **2. You're building a photo album by accident.** Content-hashed keys mean
45
- every shot stays in your bucket forever, dated and browsable. Six months in,
46
- you own something no git history gives you: what your app *looked like*,
47
- release by release. Retrospectives, launch recaps, "remember when the
48
- dashboard looked like this?" — it's all just sitting in S3.
49
-
50
- The usual capture path drags in a Playwright install, a 100MB browser
51
- download, and a place to host the image. `cliche` is a single
52
- zero-dependency CLI (and MCP server):
53
-
54
- - **Capture** — `Bun.WebView`: the system WKWebView on macOS (nothing to
55
- install), your installed Chrome via CDP on Linux/Windows. Retina-crisp PNGs.
56
- - **Upload** — `Bun.S3Client`: works with Cloudflare R2, AWS S3, MinIO,
57
- anything that speaks S3. Keys are content-hashed, so re-uploads never break
58
- old links.
59
- - **URL out** — one public URL per file on stdout (progress on stderr), or
60
- `--markdown` for `![caption](url)` lines, so you can pipe it wherever the
61
- review happens.
62
- - **MCP in** — `cliche mcp` serves the same two tools (`screenshot`, `upload`)
63
- over stdio to any MCP client, hand-rolled JSON-RPC, still zero dependencies.
64
- Everything runs locally.
65
-
66
- Requires Bun ≥ 1.4.0.
31
+ Keys are content-hashed and dated, so nothing overwrites anything. Your bucket
32
+ ends up holding what your app looked like, release by release.
67
33
 
68
34
  ## Capture
69
35
 
@@ -73,18 +39,18 @@ cliche <url> <out.png> [options]
73
39
 
74
40
  | Option | What it does |
75
41
  | --- | --- |
76
- | `--viewport <WxH>` | Viewport, default `1440x900` (`390x844` for mobile shots). |
77
- | `--wait-for <css>` | Hold the shot until a selector exists — SPAs render late. |
42
+ | `--viewport <WxH>` | Viewport, default `1440x900` (`390x844` for mobile). |
43
+ | `--full-page` | Grow the viewport to the full page height. |
44
+ | `--wait-for <css>` | Hold the shot until a selector exists. SPAs render late. |
78
45
  | `--scroll-to <css>` | Scroll a component into view before shooting. |
79
- | `--settle <ms>` | Let fonts/images/animations finish, default `1500`. |
80
- | `--full-page` | Grow the viewport to the full page height — the whole page in one shot. |
46
+ | `--settle <ms>` | Let fonts, images and animations finish. Default `1500`. |
81
47
  | `--local-storage k=v` | Seed the target origin's localStorage (repeatable). |
82
48
 
83
- The `--local-storage` flag is the trick for authenticated screens: seed your
84
- app's session token and the page boots logged in — no login form scripting.
49
+ `--local-storage` is how you shoot logged-in screens: seed the session token
50
+ and the page boots authenticated, no login form to script.
85
51
 
86
52
  ```sh
87
- cliche http://localhost:4001/admin dashboard.png \
53
+ cliche http://localhost:3000/admin dashboard.png \
88
54
  --local-storage "myapp.session-token=$TOKEN" \
89
55
  --wait-for '[data-testid=dashboard]'
90
56
  ```
@@ -92,49 +58,56 @@ cliche http://localhost:4001/admin dashboard.png \
92
58
  ## Upload
93
59
 
94
60
  ```sh
95
- cliche upload [--prefix pr-123] [--markdown] *.png # or add --upload to a capture
61
+ cliche upload [--prefix pr-123] [--markdown] *.png
96
62
  ```
97
63
 
98
- Configuration is the standard environment variables `Bun.S3Client` already
99
- reads if your shell can talk to your bucket, so can `cliche`:
64
+ Every setting is read from a `CLICHE_`-prefixed variable and passed to
65
+ `Bun.S3Client` explicitly, so cliche never picks up `S3_*` or `AWS_*`
66
+ variables your shell carries for something else.
100
67
 
101
68
  | Variable | Example |
102
69
  | --- | --- |
103
- | `S3_BUCKET` | `assets-dev` |
104
- | `S3_ENDPOINT` | `https://<account>.r2.cloudflarestorage.com` (R2) — omit for AWS |
105
- | `S3_ACCESS_KEY_ID` / `S3_SECRET_ACCESS_KEY` | your keys (`AWS_*` works too) |
106
- | `CLICHE_PUBLIC_URL` | `https://assets.example.com` the bucket's public/custom domain |
70
+ | `CLICHE_BUCKET` | `assets-dev` |
71
+ | `CLICHE_ENDPOINT` | `https://<account>.r2.cloudflarestorage.com` (omit on AWS) |
72
+ | `CLICHE_ACCESS_KEY_ID` | your access key |
73
+ | `CLICHE_SECRET_ACCESS_KEY` | your secret key |
74
+ | `CLICHE_REGION` | `auto` (defaults to `us-east-1` on AWS) |
75
+ | `CLICHE_PUBLIC_URL` | `https://assets.example.com`, the bucket's public domain |
107
76
 
108
- Objects are keyed `<prefix>/<yyyy-mm-dd>-<name>-<content-hash>.<ext>`: the
109
- hash makes re-uploads cache-safe, the date keeps the bucket browsable. The
110
- caption is derived from the file name — name files like you want them read:
111
- `mission-detail-after.png` → `![mission detail after](…)`.
77
+ Objects are keyed `<prefix>/<yyyy-mm-dd>-<name>-<content-hash>.<ext>`. The
78
+ caption comes from the file name, so name files the way you want them read:
79
+ `mission-detail-after.png` becomes `![mission detail after](…)`.
112
80
 
113
81
  > [!WARNING]
114
- > The bucket you point `cliche` at should be one you're happy to have public
115
- > (PR descriptions live forever). Never capture real user data.
82
+ > Point cliche at a bucket you're happy to have public: PR descriptions live
83
+ > forever. Never capture real user data.
116
84
 
117
- ## MCP server
85
+ ### R2 in one command
118
86
 
119
87
  ```sh
120
- cliche mcp # stdio; nothing leaves your machine except the S3 upload
88
+ bunx @voila.dev/cliche setup [--bucket my-shots]
121
89
  ```
122
90
 
123
- Registers two tools with any MCP client:
124
-
125
- - **`screenshot`** `url` (required), `out`, `viewport` (`"390x844"`),
126
- `wait_for`, `scroll_to`, `settle_ms`, `local_storage` (object), `upload`,
127
- `prefix`, `markdown`. Without `out` the shot lands in a temp file; with
128
- `upload: true` the result is the public URL.
129
- - **`upload`** — `files` (required), `prefix`, `markdown`.
91
+ Through your existing `wrangler login`, this creates the bucket, enables its
92
+ public `r2.dev` URL and writes the `CLICHE_*` block to `.env`. Wrangler can't
93
+ mint API keys, so the command prints the dashboard link for the two you paste
94
+ back in. Any other S3-compatible service works with the same variables.
130
95
 
131
- One-liners:
96
+ ## MCP server
132
97
 
133
98
  ```sh
134
- claude mcp add cliche -- bunx @voila.dev/cliche mcp # Claude Code
99
+ claude mcp add cliche -- bunx @voila.dev/cliche mcp
135
100
  ```
136
101
 
137
- or in a project's `.mcp.json`:
102
+ Two tools over stdio:
103
+
104
+ - **`screenshot`**: `url` (required), `out`, `viewport`, `full_page`,
105
+ `wait_for`, `scroll_to`, `settle_ms`, `local_storage`, `upload`, `prefix`,
106
+ `markdown`. Without `out` the shot lands in a temp file; with `upload: true`
107
+ the result is the public URL.
108
+ - **`upload`**: `files` (required), `prefix`, `markdown`.
109
+
110
+ Or in a project's `.mcp.json`:
138
111
 
139
112
  ```json
140
113
  {
@@ -144,74 +117,56 @@ or in a project's `.mcp.json`:
144
117
  }
145
118
  ```
146
119
 
147
- ## Programmatic API
148
-
149
- ```ts
150
- import { capture, upload } from "@voila.dev/cliche";
151
-
152
- await capture({
153
- url: "http://localhost:3000",
154
- out: "home.png",
155
- viewport: { width: 390, height: 844 },
156
- waitFor: "main",
157
- });
158
-
159
- const [shot] = await upload({ files: ["home.png"], prefix: "pr-7" });
160
- console.log(shot.markdown);
161
- ```
162
-
163
- ## One-command S3 setup (Cloudflare R2)
120
+ ## The album 📔
164
121
 
165
122
  ```sh
166
- bunx @voila.dev/cliche setup # or: setup --bucket my-shots
123
+ bunx @voila.dev/cliche album
167
124
  ```
168
125
 
169
- Riding your existing `wrangler login`, this creates the R2 bucket, enables
170
- its managed public `*.r2.dev` URL, and writes `S3_BUCKET`, `S3_ENDPOINT` and
171
- `CLICHE_PUBLIC_URL` to `.env`. One thing wrangler can't mint: the two S3 API
172
- keys — the command prints the exact dashboard link, you paste two values,
173
- done. Any other S3-compatible service works too with the plain env vars.
126
+ Opens your bucket as a photo album: every cliché, grouped by month, with a
127
+ filter and a lightbox. A small Bun app that ships in the package; source in
128
+ `apps/album`.
174
129
 
175
- ## The album 📔
130
+ <img src="https://raw.githubusercontent.com/voila-voila-dev/cliche/main/assets/album-preview.png" alt="album: real tries.care pages captured by cliche, grouped by month" width="100%">
176
131
 
177
- One command turns your bucket into a browsable photo album — every cliché,
178
- grouped by month, polaroid-style, with filtering and a lightbox. This is the
179
- retrospective machine:
132
+ Running on [tries.care](https://tries.care)'s screenshots bucket.
133
+
134
+ ## Claude Code skill
180
135
 
181
136
  ```sh
182
- bunx @voila.dev/cliche album # reads the same S3_* env; demo album if none
137
+ bunx @voila.dev/cliche skill
183
138
  ```
184
139
 
185
- It's a tiny Bun fullstack app (HTML imports, zero deps, of course) that
186
- ships inside the package the source lives in `apps/album`.
187
-
188
- <img src="assets/album-preview.png" alt="album — real tries.care pages captured by cliche, grouped by month as polaroids" width="100%">
140
+ Writes a PR-screenshots skill to `.claude/skills/pr-screenshots/SKILL.md`, so
141
+ Claude captures, uploads and embeds before/after shots whenever a PR touches
142
+ something visible. Also served at
143
+ [cliche.voila.dev/skill.md](https://cliche.voila.dev/skill.md).
189
144
 
190
- *(Real example: [tries.care](https://tries.care)'s pages, captured by cliche,
191
- served from its PR-screenshots bucket.)*
145
+ ## Programmatic API
192
146
 
193
- ## Claude Code skill
147
+ ```ts
148
+ import { capture, upload } from "@voila.dev/cliche";
194
149
 
195
- A ready-made [Claude Code](https://claude.com/claude-code) PR-screenshots
196
- skill ships with the package — one line installs it into your repo:
150
+ await capture({
151
+ url: "http://localhost:3000",
152
+ out: "home.png",
153
+ viewport: { width: 390, height: 844 },
154
+ waitFor: "main",
155
+ });
197
156
 
198
- ```sh
199
- bunx @voila.dev/cliche skill # writes .claude/skills/pr-screenshots/SKILL.md
157
+ const [shot] = await upload({ files: ["home.png"], prefix: "pr-7" });
158
+ console.log(shot.url);
200
159
  ```
201
160
 
202
- (Also served at [cliche.voila.dev/skill.md](https://cliche.voila.dev/skill.md)
203
- if you'd rather `curl` it.) With the skill in place, Claude captures, uploads,
204
- and embeds before/after screenshots whenever a PR touches something visible.
205
-
206
161
  ## Platform notes
207
162
 
208
- - **macOS** WKWebView, zero setup. Shots come out at the display's scale
209
- factor (2x on retina).
210
- - **Linux / Windows** drives an installed Chrome, Chromium, Edge or Brave
211
- over the Chrome DevTools Protocol (GitHub Actions runners ship Chrome, so
212
- CI capture works out of the box).
213
- - `Bun.WebView` is marked experimental by Bun; `cliche` pins none of its
214
- sharp edges and will track the API as it settles.
163
+ macOS uses the system WKWebView, nothing to install, and shots come out at the
164
+ display's scale factor. Linux and Windows drive an installed Chrome, Chromium,
165
+ Edge or Brave over the DevTools Protocol, which is why capture also works on
166
+ GitHub Actions runners.
167
+
168
+ `Bun.WebView` is marked experimental by Bun, and cliche tracks it as it
169
+ settles.
215
170
 
216
171
  ## License
217
172
 
@@ -1,4 +1,4 @@
1
- import { publicBaseUrl } from "../../../src/upload.ts";
1
+ import { createClient, publicBaseUrl } from "../../../src/upload.ts";
2
2
 
3
3
  export interface Shot {
4
4
  readonly key: string;
@@ -15,7 +15,7 @@ function dateOf(key: string, lastModified: string | undefined): string {
15
15
  }
16
16
 
17
17
  async function listBucket(baseUrl: string): Promise<Array<Shot>> {
18
- const client = new Bun.S3Client();
18
+ const client = createClient();
19
19
  const shots: Array<Shot> = [];
20
20
  let continuationToken: string | undefined;
21
21
  do {
@@ -78,7 +78,7 @@ export async function listShots(): Promise<{ demo: boolean; shots: Array<Shot> }
78
78
  return { demo: false, shots: await listBucket(baseUrl) };
79
79
  } catch (error) {
80
80
  console.error(
81
- `No bucket configured (${error instanceof Error ? error.message.split(":")[0] : error}) serving the demo album. Run \`bunx @voila.dev/cliche setup\` to plug a real one.`,
81
+ `No bucket configured (${error instanceof Error ? error.message.split(":")[0] : error}). Serving the demo album; run \`bunx @voila.dev/cliche setup\` to plug a real one.`,
82
82
  );
83
83
  return { demo: true, shots: demoShots() };
84
84
  }
package/dist/cli.js CHANGED
@@ -39,8 +39,12 @@ Upload options:
39
39
  --prefix <name> Object key prefix, e.g. pr-123.
40
40
  --markdown Print ![caption](url) lines instead of URLs.
41
41
 
42
- Upload configuration (standard Bun.S3Client environment variables):
43
- S3_BUCKET, S3_ENDPOINT, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY (or AWS_*)
42
+ Upload configuration (environment, all prefixed so nothing else collides):
43
+ CLICHE_BUCKET Bucket name.
44
+ CLICHE_ENDPOINT S3 endpoint (omit on AWS).
45
+ CLICHE_ACCESS_KEY_ID Access key.
46
+ CLICHE_SECRET_ACCESS_KEY Secret key.
47
+ CLICHE_REGION Region (defaults to us-east-1 on AWS).
44
48
  CLICHE_PUBLIC_URL Public base URL of the bucket (custom domain).
45
49
 
46
50
  URLs go to stdout, progress to stderr. Ouistiti !`;
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
package/dist/setup.js CHANGED
@@ -30,15 +30,15 @@ export function parsePublicUrl(devUrlOutput) {
30
30
  function environmentBlock(bucket, publicUrl, accountId) {
31
31
  const lines = [
32
32
  "",
33
- "# cliche added by `cliche setup` (https://cliche.voila.dev)",
34
- `S3_BUCKET=${bucket}`,
33
+ "# cliche, added by `cliche setup` (https://cliche.voila.dev)",
34
+ `CLICHE_BUCKET=${bucket}`,
35
35
  accountId === null
36
- ? "# S3_ENDPOINT=https://<account-id>.r2.cloudflarestorage.com"
37
- : `S3_ENDPOINT=https://${accountId}.r2.cloudflarestorage.com`,
36
+ ? "# CLICHE_ENDPOINT=https://<account-id>.r2.cloudflarestorage.com"
37
+ : `CLICHE_ENDPOINT=https://${accountId}.r2.cloudflarestorage.com`,
38
38
  ...(publicUrl === null ? [] : [`CLICHE_PUBLIC_URL=${publicUrl}`]),
39
39
  `# Mint the two keys at ${DASHBOARD_TOKENS_URL} (Object Read & Write on ${bucket}):`,
40
- "# S3_ACCESS_KEY_ID=",
41
- "# S3_SECRET_ACCESS_KEY=",
40
+ "# CLICHE_ACCESS_KEY_ID=",
41
+ "# CLICHE_SECRET_ACCESS_KEY=",
42
42
  "",
43
43
  ];
44
44
  return lines.join("\n");
@@ -65,8 +65,8 @@ export async function setup(bucket) {
65
65
  const publicUrl = parsePublicUrl(devUrl.output);
66
66
  const environmentFile = Bun.file(".env");
67
67
  const existing = (await environmentFile.exists()) ? await environmentFile.text() : "";
68
- if (existing.includes("S3_BUCKET=")) {
69
- console.error(".env already has an S3_BUCKET printing the block instead of appending:");
68
+ if (existing.includes("CLICHE_BUCKET=")) {
69
+ console.error(".env already has a CLICHE_BUCKET. Printing the block instead of appending:");
70
70
  console.log(environmentBlock(bucket, publicUrl, accountId));
71
71
  }
72
72
  else {
@@ -77,7 +77,7 @@ export async function setup(bucket) {
77
77
  Almost there — one last step wrangler cannot do:
78
78
  1. Open ${DASHBOARD_TOKENS_URL}
79
79
  2. Create an API token with "Object Read & Write" on "${bucket}"
80
- 3. Put the two values in .env as S3_ACCESS_KEY_ID / S3_SECRET_ACCESS_KEY
80
+ 3. Put the two values in .env as CLICHE_ACCESS_KEY_ID / CLICHE_SECRET_ACCESS_KEY
81
81
 
82
82
  Then take your first cliché:
83
83
  bunx @voila.dev/cliche https://example.com shot.png --upload`);
package/dist/setup.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"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"}
package/dist/upload.d.ts CHANGED
@@ -16,12 +16,19 @@ export interface ObjectWriter {
16
16
  type: string;
17
17
  }): Promise<unknown>;
18
18
  }
19
+ /**
20
+ * Every setting is read from a CLICHE_-prefixed variable and handed to
21
+ * Bun.S3Client explicitly, so cliche never picks up the S3_/AWS_ variables
22
+ * a shell may already carry for something else.
23
+ */
24
+ export declare function s3Options(): Bun.S3Options;
25
+ /** An S3 client for the configured bucket. */
26
+ export declare function createClient(): Bun.S3Client;
19
27
  export declare function publicBaseUrl(): string;
20
28
  /**
21
- * Upload images to the S3-compatible bucket described by the standard
22
- * environment variables Bun.S3Client already reads (S3_* / AWS_*), and
23
- * return one markdown line per file. `CLICHE_PUBLIC_URL` overrides the
24
- * public base URL (custom domains, R2 public buckets).
29
+ * Upload images to the S3-compatible bucket described by the CLICHE_
30
+ * environment variables, and return one entry per file. `CLICHE_PUBLIC_URL`
31
+ * sets the public base URL (custom domains, R2 public buckets).
25
32
  */
26
33
  export declare function upload(options: UploadOptions, writer?: ObjectWriter): Promise<Array<UploadedFile>>;
27
34
  //# sourceMappingURL=upload.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../src/upload.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACtC,8DAA8D;IAC9D,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,+CAA+C;IAC/C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,yEAAyE;AACzE,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACpF;AAED,wBAAgB,aAAa,IAAI,MAAM,CAatC;AAED;;;;;GAKG;AACH,wBAAsB,MAAM,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAoBxG"}
1
+ {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../src/upload.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACtC,8DAA8D;IAC9D,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,+CAA+C;IAC/C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,yEAAyE;AACzE,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACpF;AAED;;;;GAIG;AACH,wBAAgB,SAAS,IAAI,GAAG,CAAC,SAAS,CAkBzC;AAED,8CAA8C;AAC9C,wBAAgB,YAAY,IAAI,GAAG,CAAC,QAAQ,CAE3C;AAED,wBAAgB,aAAa,IAAI,MAAM,CAMtC;AAED;;;;GAIG;AACH,wBAAsB,MAAM,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAoBxG"}
package/dist/upload.js CHANGED
@@ -7,29 +7,49 @@ const CONTENT_TYPES = {
7
7
  ".webp": "image/webp",
8
8
  ".gif": "image/gif",
9
9
  };
10
+ /**
11
+ * Every setting is read from a CLICHE_-prefixed variable and handed to
12
+ * Bun.S3Client explicitly, so cliche never picks up the S3_/AWS_ variables
13
+ * a shell may already carry for something else.
14
+ */
15
+ export function s3Options() {
16
+ const bucket = process.env.CLICHE_BUCKET;
17
+ if (bucket === undefined) {
18
+ throw new Error("No bucket configured: set CLICHE_BUCKET (plus CLICHE_ENDPOINT, CLICHE_ACCESS_KEY_ID and CLICHE_SECRET_ACCESS_KEY). Run `cliche setup` to create one on Cloudflare R2.");
19
+ }
20
+ const endpoint = process.env.CLICHE_ENDPOINT;
21
+ const accessKeyId = process.env.CLICHE_ACCESS_KEY_ID;
22
+ const secretAccessKey = process.env.CLICHE_SECRET_ACCESS_KEY;
23
+ const region = process.env.CLICHE_REGION;
24
+ return {
25
+ bucket,
26
+ ...(endpoint === undefined ? {} : { endpoint }),
27
+ ...(accessKeyId === undefined ? {} : { accessKeyId }),
28
+ ...(secretAccessKey === undefined ? {} : { secretAccessKey }),
29
+ ...(region === undefined ? {} : { region }),
30
+ };
31
+ }
32
+ /** An S3 client for the configured bucket. */
33
+ export function createClient() {
34
+ return new Bun.S3Client(s3Options());
35
+ }
10
36
  export function publicBaseUrl() {
11
37
  const configured = process.env.CLICHE_PUBLIC_URL;
12
38
  if (configured !== undefined)
13
39
  return configured.replace(/\/$/, "");
14
- const bucket = process.env.S3_BUCKET ?? process.env.AWS_BUCKET;
15
- if (bucket === undefined) {
16
- throw new Error("No bucket configured: set S3_BUCKET (and S3_ENDPOINT + S3_ACCESS_KEY_ID + S3_SECRET_ACCESS_KEY), or CLICHE_PUBLIC_URL alone if the bucket is resolved elsewhere.");
17
- }
18
- const endpoint = process.env.S3_ENDPOINT ?? process.env.AWS_ENDPOINT;
40
+ const { bucket, endpoint, region } = s3Options();
19
41
  if (endpoint !== undefined)
20
42
  return `${endpoint.replace(/\/$/, "")}/${bucket}`;
21
- const region = process.env.AWS_REGION ?? process.env.S3_REGION ?? "us-east-1";
22
- return `https://${bucket}.s3.${region}.amazonaws.com`;
43
+ return `https://${bucket}.s3.${region ?? "us-east-1"}.amazonaws.com`;
23
44
  }
24
45
  /**
25
- * Upload images to the S3-compatible bucket described by the standard
26
- * environment variables Bun.S3Client already reads (S3_* / AWS_*), and
27
- * return one markdown line per file. `CLICHE_PUBLIC_URL` overrides the
28
- * public base URL (custom domains, R2 public buckets).
46
+ * Upload images to the S3-compatible bucket described by the CLICHE_
47
+ * environment variables, and return one entry per file. `CLICHE_PUBLIC_URL`
48
+ * sets the public base URL (custom domains, R2 public buckets).
29
49
  */
30
50
  export async function upload(options, writer) {
31
51
  const baseUrl = publicBaseUrl();
32
- const client = writer ?? new Bun.S3Client();
52
+ const client = writer ?? createClient();
33
53
  const prefix = options.prefix ?? "cliche";
34
54
  const date = new Date().toISOString().slice(0, 10);
35
55
  const uploaded = [];
@@ -1 +1 @@
1
- {"version":3,"file":"upload.js","sourceRoot":"","sources":["../src/upload.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAEnD,MAAM,aAAa,GAA2B;IAC5C,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,YAAY;IACpB,OAAO,EAAE,YAAY;IACrB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,WAAW;CACpB,CAAC;AAqBF,MAAM,UAAU,aAAa;IAC3B,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IACjD,IAAI,UAAU,KAAK,SAAS;QAAE,OAAO,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACnE,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;IAC/D,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CACb,kKAAkK,CACnK,CAAC;IACJ,CAAC;IACD,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;IACrE,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,MAAM,EAAE,CAAC;IAC9E,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,WAAW,CAAC;IAC9E,OAAO,WAAW,MAAM,OAAO,MAAM,gBAAgB,CAAC;AACxD,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,OAAsB,EAAE,MAAqB;IACxE,MAAM,OAAO,GAAG,aAAa,EAAE,CAAC;IAChC,MAAM,MAAM,GAAG,MAAM,IAAI,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;IAC5C,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,QAAQ,CAAC;IAC1C,MAAM,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACnD,MAAM,QAAQ,GAAwB,EAAE,CAAC;IACzC,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QACjC,MAAM,WAAW,GAAG,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;QAC/D,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;YAC9B,OAAO,CAAC,KAAK,CAAC,YAAY,IAAI,yBAAyB,CAAC,CAAC;YACzD,SAAS;QACX,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;QAC3C,MAAM,GAAG,GAAG,WAAW,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;QACnD,MAAM,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;QACtD,OAAO,CAAC,KAAK,CAAC,YAAY,IAAI,OAAO,GAAG,EAAE,CAAC,CAAC;QAC5C,MAAM,GAAG,GAAG,GAAG,OAAO,IAAI,GAAG,EAAE,CAAC;QAChC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,SAAS,CAAC,IAAI,CAAC,KAAK,GAAG,GAAG,EAAE,CAAC,CAAC;IAC/E,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
1
+ {"version":3,"file":"upload.js","sourceRoot":"","sources":["../src/upload.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voila.dev/cliche",
3
- "version": "0.1.10",
3
+ "version": "0.1.12",
4
4
  "type": "module",
5
5
  "packageManager": "bun@1.4.0",
6
6
  "license": "MIT",
package/skill/SKILL.md CHANGED
@@ -44,9 +44,8 @@ bunx @voila.dev/cliche upload --prefix pr-<number> --markdown qa-screenshots/*.p
44
44
  ```
45
45
 
46
46
  Prints one `![caption](url)` line per file on stdout (without `--markdown`,
47
- bare URLs). Bucket configuration
48
- comes from the standard `S3_*` environment variables plus
49
- `CLICHE_PUBLIC_URL` (see the package README).
47
+ bare URLs). Bucket configuration comes from the `CLICHE_*` environment
48
+ variables (see the package README).
50
49
 
51
50
  ## 3. Embed in the PR
52
51
 
package/src/cli.ts CHANGED
@@ -32,8 +32,12 @@ Upload options:
32
32
  --prefix <name> Object key prefix, e.g. pr-123.
33
33
  --markdown Print ![caption](url) lines instead of URLs.
34
34
 
35
- Upload configuration (standard Bun.S3Client environment variables):
36
- S3_BUCKET, S3_ENDPOINT, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY (or AWS_*)
35
+ Upload configuration (environment, all prefixed so nothing else collides):
36
+ CLICHE_BUCKET Bucket name.
37
+ CLICHE_ENDPOINT S3 endpoint (omit on AWS).
38
+ CLICHE_ACCESS_KEY_ID Access key.
39
+ CLICHE_SECRET_ACCESS_KEY Secret key.
40
+ CLICHE_REGION Region (defaults to us-east-1 on AWS).
37
41
  CLICHE_PUBLIC_URL Public base URL of the bucket (custom domain).
38
42
 
39
43
  URLs go to stdout, progress to stderr. Ouistiti !`;
package/src/setup.ts CHANGED
@@ -43,15 +43,15 @@ function environmentBlock(
43
43
  ): string {
44
44
  const lines = [
45
45
  "",
46
- "# cliche added by `cliche setup` (https://cliche.voila.dev)",
47
- `S3_BUCKET=${bucket}`,
46
+ "# cliche, added by `cliche setup` (https://cliche.voila.dev)",
47
+ `CLICHE_BUCKET=${bucket}`,
48
48
  accountId === null
49
- ? "# S3_ENDPOINT=https://<account-id>.r2.cloudflarestorage.com"
50
- : `S3_ENDPOINT=https://${accountId}.r2.cloudflarestorage.com`,
49
+ ? "# CLICHE_ENDPOINT=https://<account-id>.r2.cloudflarestorage.com"
50
+ : `CLICHE_ENDPOINT=https://${accountId}.r2.cloudflarestorage.com`,
51
51
  ...(publicUrl === null ? [] : [`CLICHE_PUBLIC_URL=${publicUrl}`]),
52
52
  `# Mint the two keys at ${DASHBOARD_TOKENS_URL} (Object Read & Write on ${bucket}):`,
53
- "# S3_ACCESS_KEY_ID=",
54
- "# S3_SECRET_ACCESS_KEY=",
53
+ "# CLICHE_ACCESS_KEY_ID=",
54
+ "# CLICHE_SECRET_ACCESS_KEY=",
55
55
  "",
56
56
  ];
57
57
  return lines.join("\n");
@@ -85,8 +85,8 @@ export async function setup(bucket: string): Promise<void> {
85
85
 
86
86
  const environmentFile = Bun.file(".env");
87
87
  const existing = (await environmentFile.exists()) ? await environmentFile.text() : "";
88
- if (existing.includes("S3_BUCKET=")) {
89
- console.error(".env already has an S3_BUCKET printing the block instead of appending:");
88
+ if (existing.includes("CLICHE_BUCKET=")) {
89
+ console.error(".env already has a CLICHE_BUCKET. Printing the block instead of appending:");
90
90
  console.log(environmentBlock(bucket, publicUrl, accountId));
91
91
  } else {
92
92
  await Bun.write(".env", existing + environmentBlock(bucket, publicUrl, accountId));
@@ -97,7 +97,7 @@ export async function setup(bucket: string): Promise<void> {
97
97
  Almost there — one last step wrangler cannot do:
98
98
  1. Open ${DASHBOARD_TOKENS_URL}
99
99
  2. Create an API token with "Object Read & Write" on "${bucket}"
100
- 3. Put the two values in .env as S3_ACCESS_KEY_ID / S3_SECRET_ACCESS_KEY
100
+ 3. Put the two values in .env as CLICHE_ACCESS_KEY_ID / CLICHE_SECRET_ACCESS_KEY
101
101
 
102
102
  Then take your first cliché:
103
103
  bunx @voila.dev/cliche https://example.com shot.png --upload`);
package/src/upload.ts CHANGED
@@ -28,30 +28,52 @@ export interface ObjectWriter {
28
28
  write(key: string, bytes: Uint8Array, options: { type: string }): Promise<unknown>;
29
29
  }
30
30
 
31
- export function publicBaseUrl(): string {
32
- const configured = process.env.CLICHE_PUBLIC_URL;
33
- if (configured !== undefined) return configured.replace(/\/$/, "");
34
- const bucket = process.env.S3_BUCKET ?? process.env.AWS_BUCKET;
31
+ /**
32
+ * Every setting is read from a CLICHE_-prefixed variable and handed to
33
+ * Bun.S3Client explicitly, so cliche never picks up the S3_/AWS_ variables
34
+ * a shell may already carry for something else.
35
+ */
36
+ export function s3Options(): Bun.S3Options {
37
+ const bucket = process.env.CLICHE_BUCKET;
35
38
  if (bucket === undefined) {
36
39
  throw new Error(
37
- "No bucket configured: set S3_BUCKET (and S3_ENDPOINT + S3_ACCESS_KEY_ID + S3_SECRET_ACCESS_KEY), or CLICHE_PUBLIC_URL alone if the bucket is resolved elsewhere.",
40
+ "No bucket configured: set CLICHE_BUCKET (plus CLICHE_ENDPOINT, CLICHE_ACCESS_KEY_ID and CLICHE_SECRET_ACCESS_KEY). Run `cliche setup` to create one on Cloudflare R2.",
38
41
  );
39
42
  }
40
- const endpoint = process.env.S3_ENDPOINT ?? process.env.AWS_ENDPOINT;
43
+ const endpoint = process.env.CLICHE_ENDPOINT;
44
+ const accessKeyId = process.env.CLICHE_ACCESS_KEY_ID;
45
+ const secretAccessKey = process.env.CLICHE_SECRET_ACCESS_KEY;
46
+ const region = process.env.CLICHE_REGION;
47
+ return {
48
+ bucket,
49
+ ...(endpoint === undefined ? {} : { endpoint }),
50
+ ...(accessKeyId === undefined ? {} : { accessKeyId }),
51
+ ...(secretAccessKey === undefined ? {} : { secretAccessKey }),
52
+ ...(region === undefined ? {} : { region }),
53
+ };
54
+ }
55
+
56
+ /** An S3 client for the configured bucket. */
57
+ export function createClient(): Bun.S3Client {
58
+ return new Bun.S3Client(s3Options());
59
+ }
60
+
61
+ export function publicBaseUrl(): string {
62
+ const configured = process.env.CLICHE_PUBLIC_URL;
63
+ if (configured !== undefined) return configured.replace(/\/$/, "");
64
+ const { bucket, endpoint, region } = s3Options();
41
65
  if (endpoint !== undefined) return `${endpoint.replace(/\/$/, "")}/${bucket}`;
42
- const region = process.env.AWS_REGION ?? process.env.S3_REGION ?? "us-east-1";
43
- return `https://${bucket}.s3.${region}.amazonaws.com`;
66
+ return `https://${bucket}.s3.${region ?? "us-east-1"}.amazonaws.com`;
44
67
  }
45
68
 
46
69
  /**
47
- * Upload images to the S3-compatible bucket described by the standard
48
- * environment variables Bun.S3Client already reads (S3_* / AWS_*), and
49
- * return one markdown line per file. `CLICHE_PUBLIC_URL` overrides the
50
- * public base URL (custom domains, R2 public buckets).
70
+ * Upload images to the S3-compatible bucket described by the CLICHE_
71
+ * environment variables, and return one entry per file. `CLICHE_PUBLIC_URL`
72
+ * sets the public base URL (custom domains, R2 public buckets).
51
73
  */
52
74
  export async function upload(options: UploadOptions, writer?: ObjectWriter): Promise<Array<UploadedFile>> {
53
75
  const baseUrl = publicBaseUrl();
54
- const client = writer ?? new Bun.S3Client();
76
+ const client = writer ?? createClient();
55
77
  const prefix = options.prefix ?? "cliche";
56
78
  const date = new Date().toISOString().slice(0, 10);
57
79
  const uploaded: Array<UploadedFile> = [];