Skip to content

Instantly share code, notes, and snippets.

@jakeisnt
Last active January 17, 2025 14:15
Show Gist options
  • Select an option

  • Save jakeisnt/1cae0f2f21c77d9dc5910f670e255fa3 to your computer and use it in GitHub Desktop.

Select an option

Save jakeisnt/1cae0f2f21c77d9dc5910f670e255fa3 to your computer and use it in GitHub Desktop.

Revisions

  1. jakeisnt renamed this gist Dec 27, 2024. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. jakeisnt created this gist Dec 27, 2024.
    85 changes: 85 additions & 0 deletions index.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,85 @@
    /**
    * - Run `npm run dev` in your terminal to start a development server
    * - Open a browser tab at http://localhost:8787/ to see your worker in action
    * - Run `npm run deploy` to publish your worker
    *
    * Bind resources to your worker in `wrangler.toml`. After adding bindings, a type definition for the
    * `Env` object can be regenerated with `npm run cf-typegen`.
    *
    * Learn more at https://developers.cloudflare.com/workers/
    */

    const B2_URL = 'YOUR_BACKBLAZE_IMAGE_URL';

    /**
    * Parse query parameters and return an object with width, height, quality, and format.
    * If no query parameters are present, return null.
    *
    * @param params - The URLSearchParams object containing query parameters.
    * @param request - The Request object.
    * @returns An object with width, height, quality, and format, or null if no query parameters are present.
    */
    const parseQueryParams = (params: URLSearchParams, request: Request) => {
    const width = Number(params.get('w') || params.get('width')) || undefined;
    const height = Number(params.get('h') || params.get('height')) || undefined;
    const quality = Number(params.get('q') || params.get('quality')) || undefined;
    const format = request.headers.get('Accept')?.includes('image/webp') ? ('webp' as const) : ('jpeg' as const);

    if (!width && !height && !quality) {
    return null;
    }

    return { width, height, quality, format };
    };

    /**
    * Return a 404 response with a message.
    *
    * @param message - The message to return in the response.
    * @returns A 404 response with the message.
    */
    const notFound = (message: string = '! img') =>
    new Response(message, {
    status: 404,
    headers: {
    'Content-Type': 'text/plain',
    'Cache-Control': 'public, max-age=3600',
    },
    });

    export default {
    async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
    const url = new URL(request.url);
    const path = url.pathname;
    const params = url.searchParams;

    if (path === '/') {
    return new Response('OK', { status: 200 });
    }

    const queryConfig = parseQueryParams(params, request);
    const b2URL = `${B2_URL}${path}`;

    const originResponse = await fetch(b2URL, {
    cf: {
    image: {
    ...queryConfig,
    fit: 'scale-down',
    },
    },
    });

    if (originResponse.ok) {
    return new Response(originResponse.body, {
    status: 200,
    headers: {
    'Cache-Control': 'public, max-age=31536000',
    'Content-Type': originResponse.headers.get('content-type') || 'image/jpeg',
    },
    });
    }

    // Return 404 if the origin image isn't found
    return notFound(`${originResponse.statusText}: ${originResponse.status}\n 'failed to fetch original image'`);
    },
    } satisfies ExportedHandler<Env>;