Automatically create shortlinks for your Astro site
TypeScript 94.0%
Nix 6.0%
7 1 1

Clone this repository

https://tangled.org/ovyerus.com/astro-shortlinks
git@knot.ovy.sh:ovyerus.com/astro-shortlinks

For self-hosted knots, clone URLs may differ based on your setup.

README.md

astro-shortlinks#

Automatically create shortlinks for your Astro site. This integration hooks into your build process to generate short URLs for your pages using various shortlink services.

Installation#

npm install astro-shortlinks
# or
pnpm add astro-shortlinks
# or
yarn add astro-shortlinks

Basic Usage#

Add the integration to your astro.config.mjs:

import { defineConfig } from "astro/config";
import shortlinks, { chhotoUrl } from "astro-shortlinks";

export default defineConfig({
  site: "https://example.com", // Required for shortlinks
  integrations: [
    shortlinks(
      chhotoUrl({
        domain: "https://short.example.com",
        apiKey: process.env.CHHOTO_API_KEY,
      }),
      {
        getPageMapping: (pages) =>
          pages.map((page) => ({
            longlink: page.toString(),
            shortlink: page.pathname.replace(/^\//, ""),
          })),
      }
    ),
  ],
});

Built-in Shortlinkers#

chhoto-url#

Creates shortlinks using a chhoto-url instance.

import { chhotoUrl } from "astro-shortlinks";

const shortlinker = chhotoUrl({
  domain: "https://short.example.com",
  apiKey: process.env.CHHOTO_API_KEY, // Optional
  resetHits: false, // Reset hit counter when updating links (default: false)
});

Creates shortlinks using a worker-links Cloudflare Worker.

import { workerLinks } from "astro-shortlinks";

const shortlinker = workerLinks({
  domain: "https://worker-links.example.workers.dev",
  secret: process.env.WORKER_LINKS_SECRET, // Required
});

multi-shortlinker#

Runs multiple shortlinkers in sequence, to create shortlinks on multiple services.

import { multiShortlinker, chhotoUrl, workerLinks } from "astro-shortlinks";

const shortlinker = multiShortlinker([
  chhotoUrl({
    domain: "https://short1.example.com",
    apiKey: process.env.CHHOTO_API_KEY,
  }),
  workerLinks({
    domain: "https://short2.example.workers.dev",
    secret: process.env.WORKER_LINKS_SECRET,
  }),
  // Add more shortlinkers as needed
]);

Configuration#

The second argument for shortlinks provides general configuration for shortlinkers.

getPageMapping#

The getPageMapping function is required and determines how your page URLs are mapped to shortlinks:

{
  getPageMapping: (pages) => {
    // pages is an array of URL objects
    return pages.map((page) => ({
      longlink: page.toString(), // Full URL of the page
      shortlink: page.pathname.replace(/^\//, ""), // Path without leading slash
    }));
  };
}

You can customize this to:

  • Use custom shortlink patterns
  • Filter out certain pages
  • Add custom prefixes or suffixes
{
  getPageMapping: (pages) => {
    return pages
      .filter((page) => !page.pathname.startsWith("/admin"))
      .map((page) => ({
        longlink: page.toString(),
        shortlink: "blog/" + page.pathname.split("/").pop(),
      }));
  };
}

Creating a Custom Shortlinker#

You can create your own shortlinker by implementing the Shortlinker interface:

import type { Shortlinker } from 'astro-shortlinks';

interface MyShortlinkerOptions {
  apiKey: string;
  domain: string;
}

export const myShortlinker = ({ apiKey, domain }: MyShortlinkerOptions): Shortlinker => {
  return {
    name: 'my-shortlinker',
    async run(mappings, logger) {
      try {
        // Your implementation here
        for (const { longlink, shortlink } of mappings) {
          const response = await fetch(`${domain}/api/create`, {
            method: 'POST',
            headers: {
              'Authorization': `Bearer ${apiKey}`,
              'Content-Type': 'application/json'
            },
            body: JSON.stringify({
              short: shortlink,
              long: longlink
            })
          });

          if (!response.ok) {
            logger.error(`Failed to create shortlink ${shortlink}: ${response.statusText}`);
            return false;
          }
        }

        logger.info(`Successfully created ${mappings.length} shortlinks`);
      } catch (error) {
        logger.error(`Error creating shortlinks: ${error}`);
        return false;
      }
    }
  };
};

Shortlinker Interface#

interface Shortlinker {
  name: string;
  run(
    mappings: PageMapping[],
    logger: AstroIntegrationLogger
  ): Promise<void | boolean>;
}

type PageMapping = {
  longlink: string; // Full URL to redirect to
  shortlink: string; // Short URL path
};

Important:

  • Return false from run() if the shortlinker fails and provides its own logging
  • The logger is namespaced to your shortlinker for better debugging
  • Handle errors gracefully and provide meaningful log messages
  • Consider supporting both creating new links and updating existing ones

Requirements#

  • Astro 5.0.0 or higher
  • The site configuration option must be set in your Astro config

Development#

A Nix flake is provided to easily set up a development environment, otherwise read it to see the current required system dependencies for developing astro-shortlinks.

# Install dependencies
pnpm install

# Build the project
pnpm build

# Development mode with TypeScript watch
pnpm dev

License#

MIT License