The Appview for the kipclip.com atproto bookmarking service

Move static assets to Bunny CDN

- Serve images from cdn.kipclip.com (replaces Cloudinary)
- Serve favicons from cdn.kipclip.com/favicons/
- Add site.webmanifest for PWA support
- Serve oauth-client-metadata.json as static response (faster)
- Remove resources folder (assets now on CDN)
- Exclude .claude/ from git and Val Town

+1
.gitignore
··· 18 18 # Editor 19 19 .vscode/ 20 20 .idea/ 21 + .claude/ 21 22 *.swp 22 23 *.swo 23 24 *~
+1
.vtignore
··· 3 3 .cursorrules 4 4 .DS_Store 5 5 .local 6 + .claude 6 7 node_modules 7 8 vendor 8 9 resources
+24 -1
backend/index.ts
··· 23 23 // OAuth routes (provides /login, /oauth/callback, /oauth-client-metadata.json, /api/auth/logout) 24 24 app.get("/login", (c) => oauth.handleLogin(c.req.raw)); 25 25 app.get("/oauth/callback", (c) => oauth.handleCallback(c.req.raw)); 26 - app.get("/oauth-client-metadata.json", () => oauth.handleClientMetadata()); 26 + // Serve static OAuth client metadata (faster than dynamic generation) 27 + app.get("/oauth-client-metadata.json", () => { 28 + return new Response( 29 + JSON.stringify({ 30 + client_name: "kipclip", 31 + client_id: "https://kipclip.com/oauth-client-metadata.json", 32 + client_uri: "https://kipclip.com", 33 + redirect_uris: ["https://kipclip.com/oauth/callback"], 34 + scope: "atproto transition:generic", 35 + grant_types: ["authorization_code", "refresh_token"], 36 + response_types: ["code"], 37 + application_type: "web", 38 + token_endpoint_auth_method: "none", 39 + dpop_bound_access_tokens: true, 40 + logo_uri: "https://cdn.kipclip.com/images/kip-vignette.png", 41 + }), 42 + { 43 + headers: { 44 + "Content-Type": "application/json", 45 + "Cache-Control": "public, max-age=3600", // Cache for 1 hour 46 + }, 47 + }, 48 + ); 49 + }); 27 50 app.post("/api/auth/logout", (c) => oauth.handleLogout(c.req.raw)); 28 51 29 52 // Session check endpoint (app-specific, returns { did, handle } for frontend)
+1 -2
backend/oauth-config.ts
··· 21 21 export const oauth = createATProtoOAuth({ 22 22 baseUrl: BASE_URL, 23 23 appName: "kipclip", 24 - logoUri: 25 - "https://res.cloudinary.com/dru3aznlk/image/upload/v1760692589/kip-vignette_h2jwct.png", 24 + logoUri: "https://cdn.kipclip.com/images/kip-vignette.png", 26 25 cookieSecret: COOKIE_SECRET, 27 26 sessionTtl: 60 * 60 * 24 * 14, // 14 days in seconds (max for public clients per AT Protocol OAuth spec) 28 27 storage: new SQLiteStorage(valTownAdapter(rawDb), {
+11 -7
frontend/index.html
··· 22 22 > 23 23 <meta 24 24 property="og:image" 25 - content="https://res.cloudinary.com/dru3aznlk/image/upload/v1760375455/kip-satchel_qtbxfx.png" 25 + content="https://cdn.kipclip.com/images/kip-satchel.png" 26 26 > 27 27 <meta property="og:image:width" content="1024"> 28 28 <meta property="og:image:height" content="1024"> ··· 44 44 > 45 45 <meta 46 46 name="twitter:image" 47 - content="https://res.cloudinary.com/dru3aznlk/image/upload/v1760375455/kip-satchel_qtbxfx.png" 47 + content="https://cdn.kipclip.com/images/kip-satchel.png" 48 48 > 49 49 <meta 50 50 name="twitter:image:alt" ··· 55 55 <link 56 56 rel="icon" 57 57 type="image/x-icon" 58 - href="https://raw.githubusercontent.com/tijs/kipclip-appview/main/resources/favicons/favicon.ico" 58 + href="https://cdn.kipclip.com/favicons/favicon.ico" 59 59 > 60 60 <link 61 61 rel="icon" 62 62 type="image/png" 63 63 sizes="16x16" 64 - href="https://raw.githubusercontent.com/tijs/kipclip-appview/main/resources/favicons/favicon-16x16.png" 64 + href="https://cdn.kipclip.com/favicons/favicon-16x16.png" 65 65 > 66 66 <link 67 67 rel="icon" 68 68 type="image/png" 69 69 sizes="32x32" 70 - href="https://raw.githubusercontent.com/tijs/kipclip-appview/main/resources/favicons/favicon-32x32.png" 70 + href="https://cdn.kipclip.com/favicons/favicon-32x32.png" 71 71 > 72 72 <link 73 73 rel="apple-touch-icon" 74 - href="https://raw.githubusercontent.com/tijs/kipclip-appview/main/resources/favicons/apple-touch-icon.png" 74 + href="https://cdn.kipclip.com/favicons/apple-touch-icon.png" 75 + > 76 + <link 77 + rel="manifest" 78 + href="https://cdn.kipclip.com/favicons/site.webmanifest" 75 79 > 76 80 77 - <!-- Mobile meta (no PWA install) --> 81 + <!-- Mobile meta --> 78 82 <meta name="theme-color" content="#FF6B6B"> 79 83 80 84 <link rel="stylesheet" href="/frontend/style.css">
resources/favicons/android-chrome-192x192.png

This is a binary file and will not be displayed.

resources/favicons/android-chrome-512x512.png

This is a binary file and will not be displayed.

resources/favicons/apple-touch-icon.png

This is a binary file and will not be displayed.

resources/favicons/favicon-16x16.png

This is a binary file and will not be displayed.

resources/favicons/favicon-32x32.png

This is a binary file and will not be displayed.

resources/favicons/favicon.ico

This is a binary file and will not be displayed.

-1
resources/favicons/site.webmanifest
··· 1 - {"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
-41
resources/kipclip-shortcut-instructions.md
··· 1 - # iOS Shortcut for kipclip 2 - 3 - ## Exact Steps to Create: 4 - 5 - 1. **Open Shortcuts app** on iPhone 6 - 2. **Tap "+" button** to create new shortcut 7 - 3. **Tap the shortcut name** at the top and name it "Kip it" 8 - 4. **Tap the info icon (i)** in the top right 9 - 5. **Toggle on "Show in Share Sheet"** 10 - - This adds "Receive [Shortcut Input] from Share Sheet" at the top 11 - automatically 12 - 6. **Tap "Shortcut Input"** (or "Any" if shown) 13 - - Under "Web", enable **"URLs"** and **"Safari web pages"** 14 - - Disable everything else for cleaner appearance 15 - 7. **Tap "Done"** to close settings 16 - 17 - 8. **Add actions to the shortcut:** 18 - - Search for and add: **"URL Encode"** 19 - - Tap "Text" and change it to **"Shortcut Input"** variable 20 - - Search for and add: **"Open URLs"** 21 - - In the URL field, type: `https://kipclip.com/save?url=` 22 - - Then tap to add the **"URL Encoded Text"** variable from previous step 23 - 24 - 9. **Done!** The shortcut is ready 25 - 26 - ## How to Share with Users: 27 - 28 - **Option 1: iCloud Link (Recommended)** 29 - 30 - 1. Tap the (···) menu on the shortcut 31 - 2. Tap "Share" 32 - 3. Select "Copy iCloud Link" 33 - 4. Share that link - users tap it and it installs automatically! 34 - 35 - **Option 2: Direct File** 36 - 37 - - Export as .shortcut file 38 - - Host on GitHub or your site 39 - - Users tap to install 40 - 41 - The iCloud link is much easier - one tap to install!