diff --git a/README.md b/README.md index 1483fab..5e11a6c 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,9 @@ -# ✂️ [kes.im](https://kes.im) URL Shortener - -[![Kes.im Homepage](./assets/images/screenshot.png)](https://kes.im) - -[![Github Actions Status](https://github.com/ramesaliyev/kes.im/actions/workflows/test-and-deploy.yml/badge.svg)](https://github.com/ramesaliyev/kes.im/actions/workflows/test-and-deploy.yml) +# [kes.im](https://kes.im) ✄ URL Shortener [![Github Actions Status](https://github.com/ramesaliyev/kes.im/actions/workflows/test-and-deploy.yml/badge.svg)](https://github.com/ramesaliyev/kes.im/actions/workflows/test-and-deploy.yml) [kes.im](https://kes.im) is an ad-less no-log URL shortener. Works on [Cloudflare Workers](https://workers.cloudflare.com/). Developed with pure front-end and workers TS code. Uses [D1](https://www.cloudflare.com/developer-platform/d1/) as database (currently migrating from KV on the fly). +[![Kes.im Homepage](./assets/images/screenshot-rocks.png)](https://kes.im) + # Architecture Overview Currently there are 3 packages: [common](./packages/common), [worker](./packages/worker/) and [site](./packages/site). **Common** is a library package used by other two. **Worker** is the actual Cloudlfare worker code which includes api and static asset server. Lastly **site** includes the front-end app and all public static assets to serve. diff --git a/assets/images/screenshot-rocks.png b/assets/images/screenshot-rocks.png new file mode 100644 index 0000000..9354407 Binary files /dev/null and b/assets/images/screenshot-rocks.png differ diff --git a/package.json b/package.json index 984517f..ef6d4d4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "kes.im", - "version": "2.1.0-beta", + "version": "2.1.0", "private": true, "type": "module", "scripts": { diff --git a/packages/worker/src/app/model.ts b/packages/worker/src/app/model.ts index 09d2f11..7a27524 100644 --- a/packages/worker/src/app/model.ts +++ b/packages/worker/src/app/model.ts @@ -118,7 +118,7 @@ export default class AppModel { // If KV has the URL, first remove it. // Then check if we should insert to D1. - this.#db.kvLinksDelete(slug); + await this.#db.kvLinksDelete(slug); // Check if D1 has URL with another slug. // If it does, we should not insert to D1 and return null. diff --git a/packages/worker/src/app/route.ts b/packages/worker/src/app/route.ts index e1e92d2..b34f44d 100644 --- a/packages/worker/src/app/route.ts +++ b/packages/worker/src/app/route.ts @@ -3,8 +3,7 @@ import App from 'app/app'; export default abstract class AppRoute { app: App; cacheable = false; - cacheControlAge: number | null = null; - cacheControlAgeMode: 'default' | 'override' = 'default'; + defaultCacheControl: string = ''; constructor(app:App) { this.app = app; @@ -29,7 +28,7 @@ export default abstract class AppRoute { // Otherwise, try to serve from cache. // If not found, serve and cache. - const {req, env, ctx} = this.app; + const {req, ctx} = this.app; const cache = (caches as any).default as Cache; const eventReq = req.getEventReq(); @@ -45,13 +44,9 @@ export default abstract class AppRoute { // Cache if response is successful. if (status in [200, 301, 302]) { - const isCacheControlSet = response.headers.has('Cache-Control'); - const isCacheControlAgeModeOverride = this.cacheControlAgeMode === 'override'; - - // Set cache headers if not already set or override mode. - if (!isCacheControlSet || isCacheControlAgeModeOverride) { - const age = this.cacheControlAge || env.CFG_DEFAULT_CACHE_AGE; - response.headers.set('Cache-Control', `max-age=${age}`); + // Use default cache control if not set. + if (!response.headers.has('Cache-Control')) { + response.headers.set('Cache-Control', this.defaultCacheControl); } // Keep worker running until the cache is updated. diff --git a/packages/worker/src/routes/redirect.ts b/packages/worker/src/routes/redirect.ts index d6dbafe..7f5f278 100644 --- a/packages/worker/src/routes/redirect.ts +++ b/packages/worker/src/routes/redirect.ts @@ -5,16 +5,8 @@ import StaticRoute from 'routes/static'; export default class RedirectRoute extends AppRoute { cacheable = true; - constructor(app:App) { - super(app); - - // Set cache control age. - this.cacheControlAge = app.env.CFG_REDIRECT_CACHE_AGE; - this.cacheControlAgeMode = 'override'; - } - async serve() { - const {req, res, model} = this.app; + const {req, res, env, model} = this.app; const slug = req.getSlug() as string; const url = await model.fetchUrlBySlug(slug); @@ -24,7 +16,7 @@ export default class RedirectRoute extends AppRoute { return res.redirect(url, { status: 301, headers: { - 'Cache-Control': `max-age=${this.cacheControlAge}`, + 'Cache-Control': `public, immutable, max-age=${env.CFG_REDIRECT_CACHE_AGE}`, 'X-Robots-Tag': 'noindex', }, }); diff --git a/packages/worker/src/routes/static.ts b/packages/worker/src/routes/static.ts index 2fbb30d..88cd427 100644 --- a/packages/worker/src/routes/static.ts +++ b/packages/worker/src/routes/static.ts @@ -8,8 +8,7 @@ export default class StaticRoute extends AppRoute { super(app); // Set cache control age. - this.cacheControlAge = app.env.CFG_DEFAULT_STATIC_CACHE_AGE; - this.cacheControlAgeMode = 'default'; + this.defaultCacheControl = `max-age=${app.env.CFG_DEFAULT_STATIC_CACHE_AGE}`; } async serve() { @@ -27,7 +26,10 @@ export default class StaticRoute extends AppRoute { // If request is for a hashed asset, set cache control to max. const isHashed = req.getEventReq().url.includes('.hashed.'); if (isHashed) { - asset.headers.set('Cache-Control', `public, immutable, max-age=${env.CFG_HASHED_STATIC_CACHE_AGE}`); + asset.headers.set( + 'Cache-Control', + `public, immutable, max-age=${env.CFG_HASHED_STATIC_CACHE_AGE}` + ); } return res.asset(asset);