@dytsou/shorten-url 2.4.4 → 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 +88 -50
- package/config/config.example.js +137 -0
- package/config/config.js +19 -0
- package/docs/about.md +360 -0
- package/docs/api/openapi.yaml +441 -81
- package/docs/flagship.md +58 -0
- package/docs/plans/2026-09-06-001-refactor-worker-hosted-react-assets-plan.md +308 -0
- package/frontend/about-template.html +124 -0
- package/frontend/index.html +17 -0
- package/frontend/package.json +20 -0
- package/frontend/pnpm-lock.yaml +1129 -0
- package/frontend/src/App.jsx +1264 -0
- package/frontend/src/api.js +272 -0
- package/frontend/src/local-flag-mock.js +55 -0
- package/frontend/src/main.jsx +4 -0
- package/frontend/src/styles/app.css +2253 -0
- package/frontend/static/favicon.svg +5 -0
- package/frontend/vite.config.js +34 -0
- package/package.json +6 -4
- package/src/lib/access.js +241 -1
- package/src/lib/assets.js +58 -0
- package/src/lib/endpoints.js +33 -8
- package/src/lib/feature-toggle.js +464 -0
- package/src/lib/flag-management.js +137 -0
- package/src/lib/flag-routes.js +155 -0
- package/src/lib/flagship.js +269 -0
- package/src/lib/observability.js +34 -0
- package/src/lib/responses.js +39 -3
- package/src/lib/runtime-config.js +90 -0
- package/src/lib/safety.js +15 -0
- package/src/lib/shortener.js +2 -2
- package/src/lib/worker-handler.js +122 -0
- package/src/worker.js +3 -66
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# URL Shortener
|
|
2
2
|
|
|
3
|
-
A URL shortener built with Cloudflare Workers, Cloudflare KV, and a responsive
|
|
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
4
|
|
|
5
5
|
[](https://cloudflare.com)
|
|
6
6
|
[](https://deploy.workers.cloudflare.com/?url=https://github.com/dytsou/shorten-url)
|
|
@@ -10,7 +10,8 @@ A URL shortener built with Cloudflare Workers, Cloudflare KV, and a responsive s
|
|
|
10
10
|
- **URL Shortening**: Create short links stored in Cloudflare KV and redirect with HTTP 302
|
|
11
11
|
- **Custom Slugs**: Optionally choose a slug using letters, numbers, hyphens, or underscores
|
|
12
12
|
- **Cloudflare Access**: The Worker checks for Cloudflare Access JWT and email headers before creating links
|
|
13
|
-
- **Responsive Design**:
|
|
13
|
+
- **Responsive Design**: Worker-hosted React interface supports desktop and mobile screens
|
|
14
|
+
- **Flagship Controls**: Shorten and protected Flagship views share one interface
|
|
14
15
|
- **Unique Links**: Optionally reuse the same short key when the destination URL already exists
|
|
15
16
|
- **URL Safety**: Validate submitted URLs and optionally check redirect destinations with Google Safe Browsing
|
|
16
17
|
- **Copy Support**: Copy shortened URLs with a manual-selection fallback
|
|
@@ -22,6 +23,30 @@ The Worker does not implement click analytics, per-IP rate limiting, or blocked-
|
|
|
22
23
|
|
|
23
24
|
## Quick Start
|
|
24
25
|
|
|
26
|
+
### Worker-hosted React frontend
|
|
27
|
+
|
|
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.
|
|
29
|
+
|
|
30
|
+
For a clean local setup, install both declared packages and use the root commands:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
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
|
|
39
|
+
```
|
|
40
|
+
|
|
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
|
+
|
|
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
|
+
|
|
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.
|
|
49
|
+
|
|
25
50
|
### Prerequisites
|
|
26
51
|
|
|
27
52
|
- A Cloudflare account with Workers and Pages; the Deploy to Cloudflare button provisions the required KV namespace
|
|
@@ -35,7 +60,7 @@ The Worker does not implement click analytics, per-IP rate limiting, or blocked-
|
|
|
35
60
|
2. Connect your Cloudflare and GitHub or GitLab accounts, then choose the destination repository and Worker name.
|
|
36
61
|
3. Confirm the `LINKS` KV binding. Cloudflare provisions the namespace and deploys the Worker from the `main` branch.
|
|
37
62
|
|
|
38
|
-
The button deploys the Worker; it does not publish
|
|
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.
|
|
39
64
|
|
|
40
65
|
### 2. Alternative: Manual Worker Deployment
|
|
41
66
|
|
|
@@ -48,33 +73,25 @@ corepack enable
|
|
|
48
73
|
pnpm install
|
|
49
74
|
```
|
|
50
75
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
```javascript
|
|
54
|
-
const config = {
|
|
55
|
-
frontend: {
|
|
56
|
-
url: "https://your-project.pages.dev/",
|
|
57
|
-
},
|
|
58
|
-
// Configure worker options here
|
|
59
|
-
};
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
`src/worker.js` imports `config/config.js` directly. Keep API keys out of this file; configure the optional Google Safe Browsing key with a Wrangler secret.
|
|
63
|
-
|
|
64
|
-
Install Wrangler, log in, and deploy:
|
|
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:
|
|
65
77
|
|
|
66
78
|
```bash
|
|
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
|
|
67
84
|
pnpm exec wrangler login
|
|
68
85
|
pnpm deploy
|
|
69
86
|
```
|
|
70
87
|
|
|
71
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.
|
|
72
89
|
|
|
73
|
-
### 3. Deploy
|
|
90
|
+
### 3. Deploy Documentation to Cloudflare Pages
|
|
74
91
|
|
|
75
|
-
The `
|
|
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.
|
|
76
93
|
|
|
77
|
-
This repository's Cloudflare Pages project publishes `docs/` from the `production` branch. The
|
|
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.
|
|
78
95
|
|
|
79
96
|
For custom error and interstitial pages, set `frontend.pagesBase` to the directory containing those files.
|
|
80
97
|
|
|
@@ -84,12 +101,13 @@ The Worker returns short URLs using the request's origin, so configure its publi
|
|
|
84
101
|
|
|
85
102
|
### Frontend Configuration
|
|
86
103
|
|
|
87
|
-
| Option
|
|
88
|
-
|
|
|
89
|
-
| `frontend.url`
|
|
90
|
-
| `frontend.pagesBase`
|
|
91
|
-
|
|
92
|
-
|
|
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 | `""` |
|
|
93
111
|
|
|
94
112
|
### Worker Configuration
|
|
95
113
|
|
|
@@ -99,7 +117,7 @@ The `frontend.displayDomain` and `frontend.theme` values in the configuration ar
|
|
|
99
117
|
| `worker.cors` | Add wildcard CORS headers for API responses | `"on"` |
|
|
100
118
|
| `worker.unique_link` | Reuse a key when the same URL has already been shortened | `true` |
|
|
101
119
|
| `worker.custom_link` | Allow custom slugs | `true` |
|
|
102
|
-
| `SAFE_BROWSING_API_KEY` | Optional Google Safe Browsing API key stored as a Worker secret
|
|
120
|
+
| `SAFE_BROWSING_API_KEY` | Optional Google Safe Browsing API key stored as a Worker secret | Unset |
|
|
103
121
|
| `worker.min_random_key_length` | Minimum length for generated keys | `6` |
|
|
104
122
|
| `worker.random_chars` | Characters used for generated keys | See config |
|
|
105
123
|
| `worker.max_custom_slug_length` | Maximum length for custom slugs | `50` |
|
|
@@ -107,12 +125,12 @@ The `frontend.displayDomain` and `frontend.theme` values in the configuration ar
|
|
|
107
125
|
|
|
108
126
|
### Security Configuration
|
|
109
127
|
|
|
110
|
-
| Option
|
|
111
|
-
|
|
|
112
|
-
| `security.rate_limit`
|
|
113
|
-
| `security.validate_urls`
|
|
114
|
-
| `security.blocked_domains`
|
|
115
|
-
| `security.block_suspicious_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 |
|
|
116
134
|
|
|
117
135
|
### Storage Configuration
|
|
118
136
|
|
|
@@ -124,9 +142,9 @@ The `frontend.displayDomain` and `frontend.theme` values in the configuration ar
|
|
|
124
142
|
|
|
125
143
|
### Custom Domain
|
|
126
144
|
|
|
127
|
-
1. Add a custom domain to the Cloudflare
|
|
128
|
-
2. Add a domain to the Cloudflare
|
|
129
|
-
3. Set `frontend.url`
|
|
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.
|
|
130
148
|
|
|
131
149
|
### Google Safe Browsing
|
|
132
150
|
|
|
@@ -156,13 +174,13 @@ These files are not included in this repository. The Worker fetches their curren
|
|
|
156
174
|
|
|
157
175
|
## 📖 API Documentation
|
|
158
176
|
|
|
159
|
-
The API reference is a static 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.
|
|
160
178
|
|
|
161
179
|
### OpenAPI Specification
|
|
162
180
|
|
|
163
181
|
- **Format**: OpenAPI 3.1.0
|
|
164
182
|
- **Location**: [docs/api/openapi.yaml](docs/api/openapi.yaml)
|
|
165
|
-
- **Interactive UI**: [docs/api/index.html](docs/api/index.html),
|
|
183
|
+
- **Interactive UI**: [docs/api/index.html](docs/api/index.html), bundled into Worker assets and served at `/api/`
|
|
166
184
|
- **Offline Access**: [docs/api/index.html](docs/api/index.html) for local viewing
|
|
167
185
|
|
|
168
186
|
### Shorten URL
|
|
@@ -176,7 +194,7 @@ The API reference is a static Swagger UI published from `docs/api/`; it is not s
|
|
|
176
194
|
}
|
|
177
195
|
```
|
|
178
196
|
|
|
179
|
-
`custom_slug` is optional. The default Worker template requires Cloudflare Access headers before creating a link.
|
|
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.
|
|
180
198
|
|
|
181
199
|
**Response (201 Created):**
|
|
182
200
|
|
|
@@ -203,9 +221,23 @@ Redirects to the stored destination with HTTP 302. Query parameters from the sho
|
|
|
203
221
|
|
|
204
222
|
### Additional Endpoints
|
|
205
223
|
|
|
206
|
-
- **GET** `/` -
|
|
224
|
+
- **GET** `/` - Serves the Worker-hosted React interface
|
|
207
225
|
- **OPTIONS** - Returns a CORS preflight response
|
|
208
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.
|
|
240
|
+
|
|
209
241
|
## 🛠️ Development
|
|
210
242
|
|
|
211
243
|
### Local Development
|
|
@@ -223,23 +255,27 @@ curl -X POST http://localhost:8787/ \
|
|
|
223
255
|
-d '{"url": "https://example.com"}'
|
|
224
256
|
```
|
|
225
257
|
|
|
226
|
-
The Worker
|
|
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.
|
|
227
259
|
|
|
228
260
|
### File Structure
|
|
229
261
|
|
|
230
262
|
```
|
|
231
263
|
shorten-url/
|
|
232
264
|
├── src/
|
|
233
|
-
│ ├── lib/ # Validation,
|
|
234
|
-
│
|
|
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
|
|
235
269
|
├── docs/
|
|
236
|
-
│ ├── index.html #
|
|
270
|
+
│ ├── index.html # Documentation site homepage
|
|
271
|
+
│ ├── about.md # Content rendered as the /about website page
|
|
237
272
|
│ └── api/
|
|
238
273
|
│ ├── index.html # Swagger UI for API docs
|
|
239
274
|
│ └── openapi.yaml # OpenAPI 3.1.0 specification
|
|
240
275
|
├── config/
|
|
241
|
-
│
|
|
242
|
-
|
|
276
|
+
│ ├── config.js # Existing deployment template
|
|
277
|
+
│ └── config.example.js # Configuration example
|
|
278
|
+
├── wrangler.toml.example # Wrangler deployment template
|
|
243
279
|
├── .github/ # GitHub workflows and templates
|
|
244
280
|
├── .gitignore # Ignores local-only files
|
|
245
281
|
└── README.md # This file
|
|
@@ -264,7 +300,8 @@ shorten-url/
|
|
|
264
300
|
|
|
265
301
|
**Worker deployment fails:**
|
|
266
302
|
|
|
267
|
-
- Confirm `src/worker.js` and `
|
|
303
|
+
- Confirm `src/worker.js`, `wrangler.toml.example`, and `frontend/` are present
|
|
304
|
+
- Build the frontend so `frontend/dist/index.html` exists
|
|
268
305
|
- Ensure the `LINKS` KV namespace ID in `wrangler.toml` is valid
|
|
269
306
|
- Ensure KV namespace ID is correct
|
|
270
307
|
- Verify you're logged into the correct Cloudflare account
|
|
@@ -277,8 +314,8 @@ shorten-url/
|
|
|
277
314
|
|
|
278
315
|
**Frontend not loading:**
|
|
279
316
|
|
|
280
|
-
-
|
|
281
|
-
- If
|
|
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 `/`
|
|
282
319
|
- Enable CORS if the frontend and Worker use different origins
|
|
283
320
|
|
|
284
321
|
**Rate limiting issues:**
|
|
@@ -307,7 +344,8 @@ If you encounter any issues or have questions:
|
|
|
307
344
|
|
|
308
345
|
## Deployment Checklist
|
|
309
346
|
|
|
310
|
-
- [ ] Set `
|
|
347
|
+
- [ ] Set `LINKS_KV_NAMESPACE_ID` and `ACCESS_ALLOWED_HOSTS` for Worker deployment
|
|
348
|
+
- [ ] Build the React frontend into `frontend/dist`
|
|
311
349
|
- [ ] Deployed `docs/` to Cloudflare Pages
|
|
312
350
|
- [ ] Created Cloudflare KV namespace
|
|
313
351
|
- [ ] Configured `wrangler.toml` with correct KV namespace ID
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* URL Shortener Configuration Example
|
|
3
|
+
*
|
|
4
|
+
* Copy this file to config.js and modify the values according to your setup.
|
|
5
|
+
* This file should be committed to your repository as a template.
|
|
6
|
+
* The actual config.js file should be added to .gitignore to keep your secrets safe.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const config = {
|
|
10
|
+
// Frontend Configuration
|
|
11
|
+
frontend: {
|
|
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: "",
|
|
21
|
+
|
|
22
|
+
// Domain displayed in the custom slug input prefix
|
|
23
|
+
// If null, will use the current domain automatically
|
|
24
|
+
// Example: "short.ly" or "yourdomain.com"
|
|
25
|
+
displayDomain: null,
|
|
26
|
+
|
|
27
|
+
// Default theme for the frontend
|
|
28
|
+
theme: "", // Use empty string for default theme, or "theme/urlcool" for urlcool theme
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
// Worker Configuration
|
|
32
|
+
worker: {
|
|
33
|
+
// Control the HTTP referrer header
|
|
34
|
+
// Set to "on" to create anonymous links that hide the HTTP Referer header
|
|
35
|
+
no_ref: "off",
|
|
36
|
+
|
|
37
|
+
// Allow Cross-origin resource sharing for API requests
|
|
38
|
+
cors: "on",
|
|
39
|
+
|
|
40
|
+
// If true, the same long URL will be shortened into the same short URL
|
|
41
|
+
unique_link: true,
|
|
42
|
+
|
|
43
|
+
// Allow users to customize the short URL
|
|
44
|
+
custom_link: true,
|
|
45
|
+
|
|
46
|
+
// Google Safe Browsing API Key for URL safety check before redirect
|
|
47
|
+
// Get your API key from: https://developers.google.com/safe-browsing/v4/get-started
|
|
48
|
+
// Leave empty to disable safety checking
|
|
49
|
+
safe_browsing_api_key: "",
|
|
50
|
+
|
|
51
|
+
// Maximum length for custom slugs
|
|
52
|
+
max_custom_slug_length: 50,
|
|
53
|
+
|
|
54
|
+
// Minimum length for generated random keys
|
|
55
|
+
min_random_key_length: 6,
|
|
56
|
+
|
|
57
|
+
// Characters used for random key generation (removed confusing characters)
|
|
58
|
+
random_chars: "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678",
|
|
59
|
+
|
|
60
|
+
// Reserved slugs that cannot be used as custom URLs
|
|
61
|
+
reserved_slugs: [
|
|
62
|
+
"api",
|
|
63
|
+
"admin",
|
|
64
|
+
"www",
|
|
65
|
+
"mail",
|
|
66
|
+
"ftp",
|
|
67
|
+
"localhost",
|
|
68
|
+
"password",
|
|
69
|
+
"help",
|
|
70
|
+
"support",
|
|
71
|
+
"contact",
|
|
72
|
+
"about",
|
|
73
|
+
"settings",
|
|
74
|
+
],
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
// KV Storage Configuration (Cloudflare Workers)
|
|
78
|
+
storage: {
|
|
79
|
+
// KV namespace binding name (must match wrangler.toml)
|
|
80
|
+
binding_name: "LINKS",
|
|
81
|
+
},
|
|
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
|
+
|
|
95
|
+
// Security Configuration
|
|
96
|
+
security: {
|
|
97
|
+
// Rate limiting (requests per minute per IP)
|
|
98
|
+
rate_limit: 10,
|
|
99
|
+
|
|
100
|
+
// Enable URL validation
|
|
101
|
+
validate_urls: true,
|
|
102
|
+
|
|
103
|
+
// Block suspicious domains
|
|
104
|
+
block_suspicious_domains: true,
|
|
105
|
+
|
|
106
|
+
// List of blocked domains (exact matches)
|
|
107
|
+
// Add domains you want to block from being shortened
|
|
108
|
+
blocked_domains: [
|
|
109
|
+
// "bit.ly",
|
|
110
|
+
// "tinyurl.com",
|
|
111
|
+
// "t.co"
|
|
112
|
+
],
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
// Analytics Configuration (optional)
|
|
116
|
+
analytics: {
|
|
117
|
+
// Enable click tracking
|
|
118
|
+
enable_tracking: false,
|
|
119
|
+
|
|
120
|
+
// Google Analytics tracking ID (GA4)
|
|
121
|
+
// Example: "G-XXXXXXXXXX"
|
|
122
|
+
ga_tracking_id: "",
|
|
123
|
+
|
|
124
|
+
// Custom analytics endpoint for tracking clicks
|
|
125
|
+
analytics_endpoint: "",
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
// Export for use in other files
|
|
130
|
+
if (typeof module !== "undefined" && module.exports) {
|
|
131
|
+
module.exports = config;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Make available globally for browser usage
|
|
135
|
+
if (typeof window !== "undefined") {
|
|
136
|
+
window.APP_CONFIG = config;
|
|
137
|
+
}
|
package/config/config.js
CHANGED
|
@@ -12,6 +12,12 @@ const config = {
|
|
|
12
12
|
// REQUIRED: Change this to your Cloudflare Pages URL or custom domain
|
|
13
13
|
url: "https://your-project.pages.dev/",
|
|
14
14
|
|
|
15
|
+
// Public Worker origin used by frontend/index.html for shortening and
|
|
16
|
+
// protected settings when the frontend is hosted separately. Keep it in
|
|
17
|
+
// sync with the HTML meta tag or VITE_WORKER_ORIGIN; leave empty when the
|
|
18
|
+
// Worker serves the page.
|
|
19
|
+
workerOrigin: "",
|
|
20
|
+
|
|
15
21
|
// Domain displayed in the custom slug input prefix
|
|
16
22
|
// If null, will use the current domain automatically
|
|
17
23
|
// Example: "short.ly" or "yourdomain.com"
|
|
@@ -63,6 +69,7 @@ const config = {
|
|
|
63
69
|
"support",
|
|
64
70
|
"contact",
|
|
65
71
|
"about",
|
|
72
|
+
"settings",
|
|
66
73
|
],
|
|
67
74
|
},
|
|
68
75
|
|
|
@@ -72,6 +79,18 @@ const config = {
|
|
|
72
79
|
binding_name: "LINKS",
|
|
73
80
|
},
|
|
74
81
|
|
|
82
|
+
// Flagship Configuration (optional until the binding and secrets are provisioned)
|
|
83
|
+
flagship: {
|
|
84
|
+
// Wrangler binding name. The Worker expects the official `env.FLAGS` binding.
|
|
85
|
+
binding_name: "FLAGS",
|
|
86
|
+
// Set in the Flagship binding block in wrangler.toml; do not put credentials here.
|
|
87
|
+
app_id: "",
|
|
88
|
+
// Worker secrets/variables used only by protected settings management:
|
|
89
|
+
// CLOUDFLARE_ACCOUNT_ID, FLAGSHIP_APP_ID, FLAGSHIP_API_TOKEN,
|
|
90
|
+
// FLAGSHIP_CSRF_SECRET, CF_ACCESS_ISSUER, CF_ACCESS_AUDIENCE,
|
|
91
|
+
// and optionally CF_ACCESS_JWKS_URL.
|
|
92
|
+
},
|
|
93
|
+
|
|
75
94
|
// Security Configuration
|
|
76
95
|
security: {
|
|
77
96
|
// Rate limiting (requests per minute per IP)
|