Automatically create shortlinks for your Astro site

docs: add README and update package.json

+255 -2
+236
README.md
··· 1 + # astro-shortlinks 2 + 3 + Automatically create shortlinks for your [Astro](https://astro.build) site. This 4 + integration hooks into your build process to generate short URLs for your pages 5 + using various shortlink services. 6 + 7 + ## Installation 8 + 9 + ```bash 10 + npm install astro-shortlinks 11 + # or 12 + pnpm add astro-shortlinks 13 + # or 14 + yarn add astro-shortlinks 15 + ``` 16 + 17 + ## Basic Usage 18 + 19 + Add the integration to your `astro.config.mjs`: 20 + 21 + ```javascript 22 + import { defineConfig } from "astro/config"; 23 + import shortlinks, { chhotoUrl } from "astro-shortlinks"; 24 + 25 + export default defineConfig({ 26 + site: "https://example.com", // Required for shortlinks 27 + integrations: [ 28 + shortlinks( 29 + chhotoUrl({ 30 + domain: "https://short.example.com", 31 + apiKey: process.env.CHHOTO_API_KEY, 32 + }), 33 + { 34 + getPageMapping: (pages) => 35 + pages.map((page) => ({ 36 + longlink: page.toString(), 37 + shortlink: page.pathname.replace(/^\//, ""), 38 + })), 39 + } 40 + ), 41 + ], 42 + }); 43 + ``` 44 + 45 + ## Built-in Shortlinkers 46 + 47 + ### chhoto-url 48 + 49 + Creates shortlinks using a 50 + [chhoto-url](https://github.com/SinTan1729/chhoto-url) instance. 51 + 52 + ```javascript 53 + import { chhotoUrl } from "astro-shortlinks"; 54 + 55 + const shortlinker = chhotoUrl({ 56 + domain: "https://short.example.com", 57 + apiKey: process.env.CHHOTO_API_KEY, // Optional 58 + resetHits: false, // Reset hit counter when updating links (default: false) 59 + }); 60 + ``` 61 + 62 + ### worker-links 63 + 64 + Creates shortlinks using a [worker-links](https://github.com/erisa/worker-links) 65 + Cloudflare Worker. 66 + 67 + ```javascript 68 + import { workerLinks } from "astro-shortlinks"; 69 + 70 + const shortlinker = workerLinks({ 71 + domain: "https://worker-links.example.workers.dev", 72 + secret: process.env.WORKER_LINKS_SECRET, // Required 73 + }); 74 + ``` 75 + 76 + ### multi-shortlinker 77 + 78 + Runs multiple shortlinkers in sequence, to create shortlinks on multiple 79 + services. 80 + 81 + ```javascript 82 + import { multiShortlinker, chhotoUrl, workerLinks } from "astro-shortlinks"; 83 + 84 + const shortlinker = multiShortlinker([ 85 + chhotoUrl({ 86 + domain: "https://short1.example.com", 87 + apiKey: process.env.CHHOTO_API_KEY, 88 + }), 89 + workerLinks({ 90 + domain: "https://short2.example.workers.dev", 91 + secret: process.env.WORKER_LINKS_SECRET, 92 + }), 93 + // Add more shortlinkers as needed 94 + ]); 95 + ``` 96 + 97 + ## Configuration 98 + 99 + The second argument for `shortlinks` provides general configuration for 100 + shortlinkers. 101 + 102 + ### `getPageMapping` 103 + 104 + The `getPageMapping` function is required and determines how your page URLs are 105 + mapped to shortlinks: 106 + 107 + ```javascript 108 + { 109 + getPageMapping: (pages) => { 110 + // pages is an array of URL objects 111 + return pages.map((page) => ({ 112 + longlink: page.toString(), // Full URL of the page 113 + shortlink: page.pathname.replace(/^\//, ""), // Path without leading slash 114 + })); 115 + }; 116 + } 117 + ``` 118 + 119 + You can customize this to: 120 + 121 + - Use custom shortlink patterns 122 + - Filter out certain pages 123 + - Add custom prefixes or suffixes 124 + 125 + ### Example: Custom Shortlink Mapping 126 + 127 + ```javascript 128 + { 129 + getPageMapping: (pages) => { 130 + return pages 131 + .filter((page) => !page.pathname.startsWith("/admin")) 132 + .map((page) => ({ 133 + longlink: page.toString(), 134 + shortlink: "blog/" + page.pathname.split("/").pop(), 135 + })); 136 + }; 137 + } 138 + ``` 139 + 140 + ## Creating a Custom Shortlinker 141 + 142 + You can create your own shortlinker by implementing the `Shortlinker` interface: 143 + 144 + ```javascript 145 + import type { Shortlinker } from 'astro-shortlinks'; 146 + 147 + interface MyShortlinkerOptions { 148 + apiKey: string; 149 + domain: string; 150 + } 151 + 152 + export const myShortlinker = ({ apiKey, domain }: MyShortlinkerOptions): Shortlinker => { 153 + return { 154 + name: 'my-shortlinker', 155 + async run(mappings, logger) { 156 + try { 157 + // Your implementation here 158 + for (const { longlink, shortlink } of mappings) { 159 + const response = await fetch(`${domain}/api/create`, { 160 + method: 'POST', 161 + headers: { 162 + 'Authorization': `Bearer ${apiKey}`, 163 + 'Content-Type': 'application/json' 164 + }, 165 + body: JSON.stringify({ 166 + short: shortlink, 167 + long: longlink 168 + }) 169 + }); 170 + 171 + if (!response.ok) { 172 + logger.error(`Failed to create shortlink ${shortlink}: ${response.statusText}`); 173 + return false; 174 + } 175 + } 176 + 177 + logger.info(`Successfully created ${mappings.length} shortlinks`); 178 + } catch (error) { 179 + logger.error(`Error creating shortlinks: ${error}`); 180 + return false; 181 + } 182 + } 183 + }; 184 + }; 185 + ``` 186 + 187 + ### Shortlinker Interface 188 + 189 + ```typescript 190 + interface Shortlinker { 191 + name: string; 192 + run( 193 + mappings: PageMapping[], 194 + logger: AstroIntegrationLogger 195 + ): Promise<void | boolean>; 196 + } 197 + 198 + type PageMapping = { 199 + longlink: string; // Full URL to redirect to 200 + shortlink: string; // Short URL path 201 + }; 202 + ``` 203 + 204 + **Important:** 205 + 206 + - Return `false` from `run()` if the shortlinker fails and provides its own 207 + logging 208 + - The logger is namespaced to your shortlinker for better debugging 209 + - Handle errors gracefully and provide meaningful log messages 210 + - Consider supporting both creating new links and updating existing ones 211 + 212 + ## Requirements 213 + 214 + - Astro 5.0.0 or higher 215 + - The `site` configuration option must be set in your Astro config 216 + 217 + ## Development 218 + 219 + A [Nix flake](./flake.nix) is provided to easily set up a development 220 + environment, otherwise read it to see the current required system dependencies 221 + for developing astro-shortlinks. 222 + 223 + ```bash 224 + # Install dependencies 225 + pnpm install 226 + 227 + # Build the project 228 + pnpm build 229 + 230 + # Development mode with TypeScript watch 231 + pnpm dev 232 + ``` 233 + 234 + ## License 235 + 236 + [MIT License](./LICENSE)
+15 -1
package.json
··· 17 17 "files": [ 18 18 "dist" 19 19 ], 20 - "keywords": [], 20 + "repository": { 21 + "type": "git", 22 + "url": "https://github.com/Ovyerus/astro-shortlinks.git" 23 + }, 24 + "keywords": [ 25 + "astro-integration", 26 + "shortlinks", 27 + "shortener", 28 + "url", 29 + "worker-links", 30 + "chhoto-url", 31 + "short" 32 + ], 33 + "bugs": "https://github.com/Ovyerus/astro-shortlinks/issues", 34 + "homepage": "https://github.com/Ovyerus/astro-shortlinks", 21 35 "packageManager": "pnpm@10.24.0", 22 36 "devDependencies": { 23 37 "@types/node": "^24.10.1",
+1 -1
src/index.ts
··· 9 9 export * from "./chhoto-url.js"; 10 10 export * from "./worker-links.js"; 11 11 12 - export default function createIntegration( 12 + export default function shortlinks( 13 13 shortlinker: Shortlinker, 14 14 options: AstroShortlinkOptions 15 15 ): AstroIntegration {
+3
src/types.ts
··· 17 17 /** 18 18 * Function to run the shortlinker over a set of {@link PageMapping}s. 19 19 * `logger` is an Astro logger that is namespaced to the shortlinker. 20 + * 21 + * Return `false` if the shortlinker failed and provided its own logging to 22 + * explain why. 20 23 */ 21 24 run( 22 25 mappings: PageMapping[],