···11+import type { AstroConfig, AstroIntegration } from "astro";
22+import type {
33+ Shortlinker,
44+ AstroShortlinkOptions,
55+ PageMapping,
66+} from "./types.js";
77+88+export * from "./types.js";
99+export * from "./chhoto-url.js";
1010+export * from "./worker-links.js";
1111+1212+export default function createIntegration(
1313+ shortlinker: Shortlinker,
1414+ options: AstroShortlinkOptions
1515+): AstroIntegration {
1616+ let config: AstroConfig;
1717+1818+ return {
1919+ name: "astro-shortlinks",
2020+ hooks: {
2121+ "astro:config:done": async ({ config: cfg }) => {
2222+ config = cfg;
2323+ },
2424+ "astro:build:done": async ({ pages, logger }) => {
2525+ if (!config.site)
2626+ return logger.error(
2727+ "The `site` Astro config option is required but has not been set. Cannot create any shortlinks."
2828+ );
2929+3030+ const siteRoot = new URL(config.base, config.site);
3131+ const pageUrls = pages.map((p) => new URL(p.pathname, siteRoot));
3232+ let pageMappings: PageMapping[];
3333+3434+ try {
3535+ pageMappings = await options.getPageMapping(pageUrls);
3636+ } catch (err) {
3737+ return logger.error(`Error while getting page mapping: ${err}`);
3838+ }
3939+4040+ if (!pageMappings.length)
4141+ return logger.warn("Empty page mapping generated, skipping.");
4242+4343+ // TODO: warn and return if there are duplicates in list
4444+4545+ logger.info(`Creating shortlinks through ${shortlinker.name}`);
4646+4747+ try {
4848+ const shortlinkerLogger = logger.fork(
4949+ `astro-shortlinks/${shortlinker.name}`
5050+ );
5151+ const succeeded = await shortlinker.run(
5252+ pageMappings,
5353+ shortlinkerLogger
5454+ );
5555+5656+ if (succeeded !== false) {
5757+ logger.info(
5858+ `Successfully created ${pageMappings.length} shortlinks!`
5959+ );
6060+ }
6161+ } catch (err) {
6262+ logger.error(
6363+ `Error while creating shortlinks with ${shortlinker.name}: ${err}`
6464+ );
6565+ }
6666+ },
6767+ },
6868+ };
6969+}
+25
src/types.ts
···11+import type { AstroIntegrationLogger } from "astro";
22+33+type Promisable<T> = Promise<T> | T;
44+/** A simple record describing the full `longlink` a `shortlink` will be pointing to. */
55+export type PageMapping = { longlink: string; shortlink: string };
66+77+export interface AstroShortlinkOptions {
88+ getPageMapping(pages: URL[]): Promisable<PageMapping[]>;
99+}
1010+1111+export interface Shortlinker {
1212+ /**
1313+ * The name of the shortlinker instance.
1414+ * Should usually be the name of the service the shortlinker is made for.
1515+ */
1616+ name: string;
1717+ /**
1818+ * Function to run the shortlinker over a set of {@link PageMapping}s.
1919+ * `logger` is an Astro logger that is namespaced to the shortlinker.
2020+ */
2121+ run(
2222+ mappings: PageMapping[],
2323+ logger: AstroIntegrationLogger
2424+ ): Promise<void | boolean>;
2525+}