@dytsou/shorten-url 2.4.3 → 2.4.5

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,231 +1,206 @@
1
1
  # URL Shortener
2
2
 
3
- A modern, fast URL shortener built with Cloudflare Workers and a responsive web interface. This project allows anyone to create short URLs with optional custom slugs, featuring a clean UI and robust backend with comprehensive API documentation.
3
+ A URL shortener built with Cloudflare Workers, Cloudflare KV, and a responsive React interface. The Worker serves the product UI and redirects, while `docs/` contains the documentation and OpenAPI reference.
4
+
5
+ [![Built with Cloudflare](https://workers.cloudflare.com/built-with-cloudflare.svg)](https://cloudflare.com)
6
+ [![Deploy to Cloudflare](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/dytsou/shorten-url)
4
7
 
5
8
  ## Features
6
9
 
7
- - **URL Shortening**: Convert long URLs into short, shareable links
8
- - **Custom Slugs**: Create personalized short URLs (optional)
9
- - **Protected Shortening**: Short URL creation is protected behind Cloudflare Access / WARP for safer usage
10
- - **Responsive Design**: Works seamlessly on desktop and mobile devices
11
- - **Fast Performance**: Built on Cloudflare Workers for global edge deployment
12
- - **Security Features**: URL validation, rate limiting, and optional Safe Browsing integration
13
- - **Modern Copy Function**: One-click copying with fallbacks for all browsers
14
- - **Custom Error Pages**: Beautiful 404, security warning, and redirect pages (fully customizable via your GitHub Pages)
15
- - **API Documentation**: Interactive Swagger UI with OpenAPI 3.1.0 specification
16
- - **Analytics Ready**: Optional click tracking and analytics integration
10
+ - **URL Shortening**: Create short links stored in Cloudflare KV and redirect with HTTP 302
11
+ - **Custom Slugs**: Optionally choose a slug using letters, numbers, hyphens, or underscores
12
+ - **Cloudflare Access**: The Worker checks for Cloudflare Access JWT and email headers before creating links
13
+ - **Responsive Design**: Worker-hosted React interface supports desktop and mobile screens
14
+ - **Flagship Controls**: Shorten and protected Flagship views share one interface
15
+ - **Unique Links**: Optionally reuse the same short key when the destination URL already exists
16
+ - **URL Safety**: Validate submitted URLs and optionally check redirect destinations with Google Safe Browsing
17
+ - **Copy Support**: Copy shortened URLs with a manual-selection fallback
18
+ - **Hosted Error Pages**: Configure external 404, error, Safe Browsing warning, and no-referrer pages
19
+ - **API Documentation**: Static Swagger UI with an OpenAPI 3.1 specification
20
+ - **Worker Observability**: Structured logs and traces are supported
21
+
22
+ The Worker does not implement click analytics, per-IP rate limiting, or blocked-domain lists. The similarly named settings in `config/config.js` are not used by the current Worker.
17
23
 
18
24
  ## Quick Start
19
25
 
20
- ### Prerequisites
26
+ ### Worker-hosted React frontend
21
27
 
22
- - A Cloudflare account with Workers enabled
23
- - GitHub account for hosting the frontend (or any static hosting)
24
- - Basic knowledge of Git and command line
28
+ The product UI is React source in `frontend/`, compiled to `frontend/dist`, and served by the Worker through its `ASSETS` binding. Worker routing and APIs remain in `src/`; the API reference from `docs/api/` is bundled into Worker assets at `/api/` and `/api/openapi.yaml`. The separate Cloudflare Pages site can publish the documentation landing page from `docs/`; `docs/index.html` is not a product asset.
25
29
 
26
- ### 1. Clone the Repository
30
+ For a clean local setup, install both declared packages and use the root commands:
27
31
 
28
32
  ```bash
29
- git clone https://github.com/dytsou/shorten-url.git
30
- cd shorten-url
33
+ pnpm install --frozen-lockfile --ignore-scripts
34
+ pnpm --dir frontend install --frozen-lockfile --ignore-scripts
35
+ cp wrangler.toml.example wrangler.toml
36
+ # Set a real LINKS namespace and production-only Access values in wrangler.toml or secrets.
37
+ pnpm build
38
+ pnpm dev
31
39
  ```
32
40
 
33
- ### 2. Setup Configuration
34
-
35
- ```bash
36
- # Copy the example configuration
37
- cp config/config.example.js config/config.js
38
-
39
- # Edit the configuration file
40
- vim config/config.js
41
- ```
41
+ `pnpm dev`, `pnpm preview`, and `pnpm deploy` build `frontend/dist` before running Wrangler. The Worker serves the UI at `GET /`. Only the `production` branch mounts its product page at `/shorten`; other branch previews stay at `/`. Regardless of the page path, the UI sends API requests to `POST /` and `/settings/api/*`. Standalone settings pages are not exposed.
42
42
 
43
- Update the `config/config.js` file with your settings:
43
+ Production must use an Access-protected custom hostname, set `workers_dev = false`, and set `ACCESS_ALLOWED_HOSTS` to that hostname. Keep `CLOUDFLARE_API_TOKEN`, `FLAGSHIP_CSRF_SECRET`, and provider credentials in Cloudflare/GitHub secrets, never Vite metadata or tracked configuration. Optional `FRONTEND_URL` and `FRONTEND_PAGES_BASE` retain legacy error/interstitial pages only; they are not used to serve the normal UI.
44
44
 
45
- ```javascript
46
- const config = {
47
- frontend: {
48
- // IMPORTANT: Update this to your GitHub Pages URL or custom domain
49
- url: "https://yourusername.github.io/shorten-url/",
50
- },
51
- // ... other settings
52
- };
53
- ```
45
+ The Worker deployment workflow reads the non-secret GitHub variables
46
+ `LINKS_KV_NAMESPACE_ID` and `ACCESS_ALLOWED_HOSTS`, plus the
47
+ `CLOUDFLARE_API_TOKEN` secret, to create its ignored `wrangler.toml` at build
48
+ time.
54
49
 
55
- ### 3. Deploy Frontend
50
+ ### Prerequisites
56
51
 
57
- #### Option A: GitHub Pages (Recommended)
52
+ - A Cloudflare account with Workers and Pages; the Deploy to Cloudflare button provisions the required KV namespace
53
+ - A GitHub or GitLab account to receive the repository created by the Deploy to Cloudflare button
54
+ - A Cloudflare Pages project to publish `docs/`
55
+ - Node.js 24 or newer and pnpm 10.22.0 for manual deployment
58
56
 
59
- 1. Push your code to GitHub
60
- 2. Go to your repository settings
61
- 3. Enable GitHub Pages for the main branch
62
- 4. Your frontend will be available at `https://yourusername.github.io/shorten-url/`
57
+ ### 1. Deploy with Cloudflare (Recommended)
63
58
 
64
- #### Option B: Custom Domain
59
+ 1. Click the **Deploy to Cloudflare** button near the top of this README.
60
+ 2. Connect your Cloudflare and GitHub or GitLab accounts, then choose the destination repository and Worker name.
61
+ 3. Confirm the `LINKS` KV binding. Cloudflare provisions the namespace and deploys the Worker from the `main` branch.
65
62
 
66
- 1. Upload the `docs/` directory to your web hosting
67
- 2. Update the `frontend.url` in `config/config.js` to match your domain
63
+ The button deploys the Worker; it does not publish `docs/`. Connect the created repository to Cloudflare Pages, leave the build command blank, and set the output directory to `docs`. The React product UI is built into `frontend/dist` and served by the Worker through `ASSETS`; use the Worker deployment workflow or `pnpm deploy` to build and deploy those assets.
68
64
 
69
- ### 4. Setup Cloudflare Workers
65
+ ### 2. Alternative: Manual Worker Deployment
70
66
 
71
- #### Install Wrangler CLI
67
+ Clone the repository and install the pinned Wrangler version:
72
68
 
73
69
  ```bash
74
- npm install -g wrangler
70
+ git clone https://github.com/dytsou/shorten-url.git
71
+ cd shorten-url
72
+ corepack enable
73
+ pnpm install
75
74
  ```
76
75
 
77
- #### Configure Wrangler
76
+ The Worker serves the product UI from `ASSETS`. To deploy manually, install both packages, create the local Wrangler file from the tracked example, set the `LINKS` namespace ID and Access hostname, then build and deploy:
78
77
 
79
78
  ```bash
80
- # Login to Cloudflare
81
- wrangler auth login
82
-
83
- # Create a new KV namespace for storing URLs
84
- wrangler kv:namespace create "LINKS"
79
+ pnpm install --frozen-lockfile --ignore-scripts
80
+ pnpm --dir frontend install --frozen-lockfile --ignore-scripts
81
+ cp wrangler.toml.example wrangler.toml
82
+ # Set the LINKS namespace ID and ACCESS_ALLOWED_HOSTS.
83
+ pnpm build
84
+ pnpm exec wrangler login
85
+ pnpm deploy
85
86
  ```
86
87
 
87
- #### Create wrangler.toml
88
+ The `LINKS` binding in `wrangler.toml` omits an account-specific namespace ID so Wrangler can provision it. To use an existing KV namespace, create it with `pnpm exec wrangler kv namespace create LINKS` and set its ID in `wrangler.toml` before deploying.
88
89
 
89
- Create a `wrangler.toml` file in your project root:
90
+ ### 3. Deploy Documentation to Cloudflare Pages
90
91
 
91
- ```toml
92
- name = "url-shortener"
93
- main = "src/worker.js"
94
- compatibility_date = "2024-01-01"
92
+ The `docs/` directory contains the API reference and documentation. To create a Pages site, connect your repository, set the production branch to the branch containing your documentation, leave the build command blank, and use `docs` as the output directory.
95
93
 
96
- [[kv_namespaces]]
97
- binding = "LINKS"
98
- id = "your-kv-namespace-id-here"
99
- ```
100
-
101
- Replace `your-kv-namespace-id-here` with the ID from the KV namespace creation command.
94
+ This repository's Cloudflare Pages project publishes `docs/` from the `production` branch. The product UI is served by the Worker and does not depend on the Pages site.
102
95
 
103
- #### Deploy the Worker
96
+ For custom error and interstitial pages, set `frontend.pagesBase` to the directory containing those files.
104
97
 
105
- ```bash
106
- wrangler deploy
107
- ```
108
-
109
- ### 5. Update Configuration
110
-
111
- After deploying, update your `config/config.js` with the worker URL:
112
-
113
- ```javascript
114
- const config = {
115
- frontend: {
116
- url: "https://yourusername.github.io/shorten-url/",
117
- },
118
- // ... other settings
119
- };
120
- ```
98
+ The Worker returns short URLs using the request's origin, so configure its public domain in Cloudflare separately from `frontend.url`.
121
99
 
122
100
  ## ⚙️ Configuration Options
123
101
 
124
102
  ### Frontend Configuration
125
103
 
126
- | Option | Description | Default |
127
- | ------------------------ | --------------------------------------- | -------- |
128
- | `frontend.url` | URL where your frontend is hosted | Required |
129
- | `frontend.displayDomain` | Domain shown in UI (null = auto-detect) | `null` |
130
- | `frontend.theme` | UI theme selection | `""` |
104
+ | Option | Description | Default |
105
+ | ------------------------ | ------------------------------------------------------- | ------- |
106
+ | `frontend.url` | Optional origin for legacy error and interstitial pages | `""` |
107
+ | `frontend.pagesBase` | Base URL for hosted error and interstitial pages | `url` |
108
+ | `frontend.workerOrigin` | Public Worker origin for a separately hosted frontend | `""` |
109
+ | `frontend.displayDomain` | Domain shown in UI (null = auto-detect) | `null` |
110
+ | `frontend.theme` | UI theme selection | `""` |
131
111
 
132
112
  ### Worker Configuration
133
113
 
134
- | Option | Description | Default |
135
- | ------------------------------- | --------------------------------- | ---------- |
136
- | `worker.no_ref` | Hide HTTP referrer header | `"off"` |
137
- | `worker.cors` | Enable CORS for API requests | `"on"` |
138
- | `worker.unique_link` | Same URL = same short link | `true` |
139
- | `worker.custom_link` | Allow custom slugs | `true` |
140
- | `worker.safe_browsing_api_key` | Google Safe Browsing API key | `""` |
141
- | `worker.min_random_key_length` | Minimum length for generated keys | `6` |
142
- | `worker.max_custom_slug_length` | Maximum length for custom slugs | `50` |
143
- | `worker.reserved_slugs` | List of reserved slugs | See config |
114
+ | Option | Description | Default |
115
+ | ------------------------------- | --------------------------------------------------------------- | ---------- |
116
+ | `worker.no_ref` | Use the hosted no-referrer interstitial before redirecting | `"off"` |
117
+ | `worker.cors` | Add wildcard CORS headers for API responses | `"on"` |
118
+ | `worker.unique_link` | Reuse a key when the same URL has already been shortened | `true` |
119
+ | `worker.custom_link` | Allow custom slugs | `true` |
120
+ | `SAFE_BROWSING_API_KEY` | Optional Google Safe Browsing API key stored as a Worker secret | Unset |
121
+ | `worker.min_random_key_length` | Minimum length for generated keys | `6` |
122
+ | `worker.random_chars` | Characters used for generated keys | See config |
123
+ | `worker.max_custom_slug_length` | Maximum length for custom slugs | `50` |
124
+ | `worker.reserved_slugs` | Slugs that cannot be used as custom links | See config |
144
125
 
145
126
  ### Security Configuration
146
127
 
147
- | Option | Description | Default |
148
- | -------------------------- | -------------------------- | ------- |
149
- | `security.rate_limit` | Requests per minute per IP | `10` |
150
- | `security.validate_urls` | Enable URL validation | `true` |
151
- | `security.blocked_domains` | List of blocked domains | `[]` |
128
+ | Option | Description | Default |
129
+ | ----------------------------------- | ------------------------------------------------------------------ | ------- |
130
+ | `security.rate_limit` | Not implemented by the Worker | Unused |
131
+ | `security.validate_urls` | URLs are always validated; this setting does not toggle validation | Unused |
132
+ | `security.blocked_domains` | Domain blocklists are not implemented by the Worker | Unused |
133
+ | `security.block_suspicious_domains` | Domain blocklists are not implemented by the Worker | Unused |
152
134
 
153
135
  ### Storage Configuration
154
136
 
155
- | Option | Description | Default |
156
- | ---------------------- | ------------------------- | --------- |
157
- | `storage.binding_name` | KV namespace binding name | `"LINKS"` |
137
+ | Option | Description | Default |
138
+ | ---------------------- | -------------------------------------------------------------------- | --------- |
139
+ | `storage.binding_name` | Worker reads KV from `env.LINKS`; this config value is not consulted | `"LINKS"` |
158
140
 
159
141
  ## 🔧 Advanced Setup
160
142
 
161
143
  ### Custom Domain
162
144
 
163
- 1. Add a custom domain in Cloudflare Workers dashboard
164
- 2. Update your DNS records to point to Cloudflare
165
- 3. Update the worker URL in your configuration
145
+ 1. Add a custom domain to the Cloudflare Worker and protect it with Cloudflare Access.
146
+ 2. Add a custom domain to the Cloudflare Pages project for documentation.
147
+ 3. Set `frontend.url` only when using separately hosted legacy error or interstitial pages.
166
148
 
167
149
  ### Google Safe Browsing
168
150
 
169
151
  1. Get an API key from [Google Cloud Console](https://developers.google.com/safe-browsing/v4/get-started)
170
- 2. Add the key to your `config.js`:
152
+ 2. Store it as a Worker secret:
171
153
 
172
- ```javascript
173
- worker: {
174
- safe_browsing_api_key: "your-api-key-here",
175
- }
154
+ ```bash
155
+ pnpm exec wrangler secret put SAFE_BROWSING_API_KEY
176
156
  ```
177
157
 
158
+ The Worker reads this secret at runtime. The key is not stored in `config/config.js`.
159
+
178
160
  ### Analytics Integration
179
161
 
180
- Configure analytics in your `config.js`:
181
-
182
- ```javascript
183
- analytics: {
184
- enable_tracking: true,
185
- ga_tracking_id: "G-XXXXXXXXXX", // Google Analytics 4
186
- analytics_endpoint: "https://your-analytics-endpoint.com"
187
- }
188
- ```
162
+ Click analytics is not implemented, and the `analytics` object in `config/config.js` is not used by the Worker. Cloudflare Worker logs and traces are enabled in `wrangler.toml`.
189
163
 
190
164
  ### Custom Error Pages
191
165
 
192
- The system fetches error and redirect pages from your GitHub Pages repository, so you can fully customize their content and design:
193
-
194
- - **404 Page**: <code>https://dytsou.github.io/404.html</code>
195
- - **Security Warning**: <code>https://dytsou.github.io/safe-browsing-warning.html</code>
196
- - **No-Referrer Redirect**: <code>https://dytsou.github.io/no-ref-page.html</code>
166
+ The Worker fetches optional error and interstitial pages from `frontend.pagesBase` (or `frontend.url` when `pagesBase` is not set). Add these files to your static host to customize them:
197
167
 
198
- You can edit these HTML files in your GitHub Pages repo to change the look, text, or behavior at any time. The worker will always serve the latest version from your site.
168
+ - **404 Page**: `404.html`
169
+ - **Error Page**: `error.html`
170
+ - **Security Warning**: `safe-browsing-warning.html`
171
+ - **No-Referrer Redirect**: `no-ref-page.html`
199
172
 
200
- All pages feature responsive design with glassmorphism effects matching your main interface.
173
+ These files are not included in this repository. The Worker fetches their current contents from your static host when needed.
201
174
 
202
175
  ## 📖 API Documentation
203
176
 
204
- The project includes comprehensive API documentation available at `/api` endpoint with interactive Swagger UI.
177
+ The API reference is a static Swagger UI built from `docs/api/` and bundled into Worker assets. `/api` redirects to `/api/`, where the interactive reference is served.
205
178
 
206
179
  ### OpenAPI Specification
207
180
 
208
181
  - **Format**: OpenAPI 3.1.0
209
182
  - **Location**: [docs/api/openapi.yaml](docs/api/openapi.yaml)
210
- - **Interactive UI**: Available at `/api` endpoint on your deployed worker
183
+ - **Interactive UI**: [docs/api/index.html](docs/api/index.html), bundled into Worker assets and served at `/api/`
211
184
  - **Offline Access**: [docs/api/index.html](docs/api/index.html) for local viewing
212
185
 
213
186
  ### Shorten URL
214
187
 
215
- **POST** `/shorten`
188
+ **POST** `/`
216
189
 
217
190
  ```json
218
191
  {
219
192
  "url": "https://example.com/very-long-url",
220
- "custom_slug": "my-link" // optional
193
+ "custom_slug": "my-link"
221
194
  }
222
195
  ```
223
196
 
224
- **Response:**
197
+ The endpoint stays at the origin root even when the production page is mounted at `/shorten`. `custom_slug` is optional. The default Worker template requires Cloudflare Access headers before creating a link.
198
+
199
+ **Response (201 Created):**
225
200
 
226
201
  ```json
227
202
  {
228
- "short_url": "https://url.tsou.me/abc123"
203
+ "short_url": "https://your-worker-domain.example/abc123"
229
204
  }
230
205
  ```
231
206
 
@@ -242,11 +217,26 @@ The project includes comprehensive API documentation available at `/api` endpoin
242
217
 
243
218
  **GET** `/{key}`
244
219
 
245
- Redirects to the original URL or shows appropriate error page.
220
+ Redirects to the stored destination with HTTP 302. Query parameters from the short URL are appended to the destination.
246
221
 
247
222
  ### Additional Endpoints
248
223
 
249
- - **GET** `/api` - Interactive API documentation (Swagger UI)
224
+ - **GET** `/` - Serves the Worker-hosted React interface
225
+ - **OPTIONS** - Returns a CORS preflight response
226
+
227
+ ### Flagship Management API
228
+
229
+ The authenticated control plane manages the `shorten-routing` flag under `/settings/api`. Requests require Cloudflare Access authentication. Fetch a CSRF token before sending a write; POST and PUT requests must include that token in `X-CSRF-Token`, use `application/json`, and come from the same origin as the UI.
230
+
231
+ | Method | Path | Purpose |
232
+ | ------ | -------------------------------------------- | --------------------------------------------------------- |
233
+ | `GET` | `/settings/api/csrf` | Get a CSRF token for the signed-in Access user and origin |
234
+ | `GET` | `/settings/api/flags` | Read the saved shortening flag |
235
+ | `POST` | `/settings/api/flag` | Create the `shorten-routing` flag |
236
+ | `PUT` | `/settings/api/flag/shorten-routing` | Save a draft with `expectedUpdatedAt` concurrency control |
237
+ | `POST` | `/settings/api/flag/shorten-routing/publish` | Publish the saved version |
238
+
239
+ Targeting rules are evaluated by ascending priority. Conditions in a rule are combined with AND and can target country, region, continent, timezone, browser language, or UTM source, medium, and campaign. Supported operators are `equals`, `not_equals`, `contains`, `starts_with`, `ends_with`, `in`, and `not_in`. A rule can also set `rolloutPercentage` from 0 to 100; the Worker uses a stable visitor key for the canary assignment. See the OpenAPI schema for request and response shapes.
250
240
 
251
241
  ## 🛠️ Development
252
242
 
@@ -254,45 +244,50 @@ Redirects to the original URL or shows appropriate error page.
254
244
 
255
245
  ```bash
256
246
  # Start local development server (see wrangler.toml for port / host)
257
- wrangler dev
247
+ pnpm dev
258
248
 
259
- # Test with curl (example; in production, requests must pass through Cloudflare Access/WARP)
260
- curl -X POST http://localhost:8787/shorten \
249
+ # Local-only example. The handler checks for both headers; Cloudflare Access must
250
+ # authenticate production requests before they reach the Worker.
251
+ curl -X POST http://localhost:8787/ \
261
252
  -H "Content-Type: application/json" \
253
+ -H "Cf-Access-Jwt-Assertion: local-test" \
254
+ -H "Cf-Access-Authenticated-User-Email: you@example.com" \
262
255
  -d '{"url": "https://example.com"}'
263
256
  ```
264
257
 
258
+ The Worker combines built-in defaults with non-secret Wrangler variables; keep credentials in Wrangler secrets. Run `pnpm test` to execute the Worker tests.
259
+
265
260
  ### File Structure
266
261
 
267
262
  ```
268
263
  shorten-url/
269
264
  ├── src/
270
- │ ├── worker.js # Production Cloudflare Worker
271
- │ ├── worker.dev.js # Development Cloudflare Worker
272
- │ └── worker.example.js # Worker template
265
+ │ ├── lib/ # Validation, routes, KV, assets, and observability
266
+ │ ├── worker.js # Production Worker entrypoint
267
+ │ └── worker.example.js # Example Worker entrypoint
268
+ ├── frontend/ # React product UI, about-page template, and build configuration
273
269
  ├── docs/
274
- │ ├── index.html # Homepage interface
270
+ │ ├── index.html # Documentation site homepage
271
+ │ ├── about.md # Content rendered as the /about website page
275
272
  │ └── api/
276
273
  │ ├── index.html # Swagger UI for API docs
277
274
  │ └── openapi.yaml # OpenAPI 3.1.0 specification
278
275
  ├── config/
279
- │ ├── config.js # Configuration (not in git)
280
- │ └── config.example.js # Configuration template
281
- ├── .cursor/ # Cursor IDE rules and workflow
276
+ │ ├── config.js # Existing deployment template
277
+ │ └── config.example.js # Configuration example
278
+ ├── wrangler.toml.example # Wrangler deployment template
282
279
  ├── .github/ # GitHub workflows and templates
283
- ├── .gitignore # Git ignore rules
284
- ├── README.md # This file
285
- └── wrangler.toml # Wrangler configuration
280
+ ├── .gitignore # Ignores local-only files
281
+ └── README.md # This file
286
282
  ```
287
283
 
288
284
  ## Security Considerations
289
285
 
290
- - Keep your `config.js` file private (it's in `.gitignore`)
291
- - Use environment variables for sensitive data in production
292
- - Enable rate limiting to prevent abuse
293
- - Consider enabling Google Safe Browsing for malicious URL detection
286
+ - Keep API keys out of version control; store them with Wrangler secrets
287
+ - Configure a Cloudflare Access policy in front of the Worker; the handler checks for Access headers but does not verify JWT signatures itself
288
+ - The Worker has no built-in per-IP rate limit or blocked-domain list
289
+ - Consider enabling Google Safe Browsing for redirect destinations
294
290
  - Regularly monitor your KV storage usage
295
- - Configure Cloudflare Access / WARP correctly, as URL shortening is intended to be available only to authenticated/requesters you control
296
291
 
297
292
  ## Troubleshooting
298
293
 
@@ -305,7 +300,9 @@ shorten-url/
305
300
 
306
301
  **Worker deployment fails:**
307
302
 
308
- - Check your `wrangler.toml` configuration
303
+ - Confirm `src/worker.js`, `wrangler.toml.example`, and `frontend/` are present
304
+ - Build the frontend so `frontend/dist/index.html` exists
305
+ - Ensure the `LINKS` KV namespace ID in `wrangler.toml` is valid
309
306
  - Ensure KV namespace ID is correct
310
307
  - Verify you're logged into the correct Cloudflare account
311
308
 
@@ -317,13 +314,13 @@ shorten-url/
317
314
 
318
315
  **Frontend not loading:**
319
316
 
320
- - Update `frontend.url` in your config to match your hosting URL
321
- - Ensure CORS is enabled in worker configuration
317
+ - Check that the Worker has an `ASSETS` binding and `frontend/dist/index.html` was built
318
+ - If shortening returns an invalid-path response, check that the frontend POST path is `/`
319
+ - Enable CORS if the frontend and Worker use different origins
322
320
 
323
321
  **Rate limiting issues:**
324
322
 
325
- - Adjust `security.rate_limit` in your configuration
326
- - Consider implementing IP allowlisting for trusted sources
323
+ - The Worker does not currently rate-limit requests. Protect shortening with Cloudflare Access or add a rate limiter.
327
324
 
328
325
  ## License
329
326
 
@@ -347,12 +344,14 @@ If you encounter any issues or have questions:
347
344
 
348
345
  ## Deployment Checklist
349
346
 
350
- - [ ] Updated `config.js` with your settings
351
- - [ ] Deployed frontend to GitHub Pages or custom hosting
347
+ - [ ] Set `LINKS_KV_NAMESPACE_ID` and `ACCESS_ALLOWED_HOSTS` for Worker deployment
348
+ - [ ] Build the React frontend into `frontend/dist`
349
+ - [ ] Deployed `docs/` to Cloudflare Pages
352
350
  - [ ] Created Cloudflare KV namespace
353
351
  - [ ] Configured `wrangler.toml` with correct KV namespace ID
354
- - [ ] Deployed worker using `wrangler deploy`
355
- - [ ] Tested URL shortening functionality
352
+ - [ ] Protected the Worker with a Cloudflare Access policy
353
+ - [ ] Deployed the Worker using `pnpm deploy`
354
+ - [ ] Tested URL shortening at `POST /`
356
355
  - [ ] Verified copy-to-clipboard feature works
357
356
  - [ ] Tested custom error pages (404, security warnings)
358
357
  - [ ] (Optional) Configured custom domain
@@ -9,9 +9,15 @@
9
9
  const config = {
10
10
  // Frontend Configuration
11
11
  frontend: {
12
- // URL where your frontend is hosted (used by worker to serve the main page)
13
- // REQUIRED: Change this to your GitHub Pages URL or custom domain
14
- url: "https://yourusername.github.io/your-repo-name/",
12
+ // Leave empty when the Worker serves the React UI. Set this only for
13
+ // separately hosted legacy error/interstitial pages.
14
+ url: "",
15
+
16
+ // Public Worker origin used by frontend/index.html for shortening and
17
+ // protected settings APIs when the frontend is hosted separately. Keep it in
18
+ // sync with the HTML meta tag or VITE_WORKER_ORIGIN; leave empty when the
19
+ // Worker serves the page.
20
+ workerOrigin: "",
15
21
 
16
22
  // Domain displayed in the custom slug input prefix
17
23
  // If null, will use the current domain automatically
@@ -64,6 +70,7 @@ const config = {
64
70
  "support",
65
71
  "contact",
66
72
  "about",
73
+ "settings",
67
74
  ],
68
75
  },
69
76
 
@@ -73,6 +80,18 @@ const config = {
73
80
  binding_name: "LINKS",
74
81
  },
75
82
 
83
+ // Flagship Configuration (optional until the binding and secrets are provisioned)
84
+ flagship: {
85
+ // Wrangler binding name. The Worker expects the official `env.FLAGS` binding.
86
+ binding_name: "FLAGS",
87
+ // Set in the Flagship binding block in wrangler.toml; do not put credentials here.
88
+ app_id: "",
89
+ // Worker secrets/variables used only by protected settings management:
90
+ // CLOUDFLARE_ACCOUNT_ID, FLAGSHIP_APP_ID, FLAGSHIP_API_TOKEN,
91
+ // FLAGSHIP_CSRF_SECRET, CF_ACCESS_ISSUER, CF_ACCESS_AUDIENCE,
92
+ // and optionally CF_ACCESS_JWKS_URL.
93
+ },
94
+
76
95
  // Security Configuration
77
96
  security: {
78
97
  // Rate limiting (requests per minute per IP)