Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 1 addition & 6 deletions apps/api/src/routes/content/collections.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { FastifyPluginAsync } from "fastify";
import { env } from "@playfulprogramming/common";
import { db, posts } from "@playfulprogramming/db";
import { Type, type Static } from "typebox";
import { eq } from "drizzle-orm";
import { createImageUrl } from "../../utils.ts";

const CollectionsQueryParamsSchema = Type.Object({
locale: Type.String({ default: "en" }),
Expand Down Expand Up @@ -71,11 +71,6 @@ const CollectionsResponseSchema = Type.Array(

type CollectionsResponse = Static<typeof CollectionsResponseSchema>;

function createImageUrl(path: string): string {
const s3PublicUrl = `${env.S3_PUBLIC_URL}/${env.S3_BUCKET}/`;
return new URL(path, s3PublicUrl).toString();
}

const collectionsRoutes: FastifyPluginAsync = async (fastify) => {
fastify.get<{
Querystring: Static<typeof CollectionsQueryParamsSchema>;
Expand Down
9 changes: 3 additions & 6 deletions apps/api/src/routes/tasks/post-images.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import type { FastifyPluginAsync } from "fastify";
import { env } from "@playfulprogramming/common";
import { db } from "@playfulprogramming/db";
import { Type, type Static } from "typebox";
import {
type PostImageOutput,
Tasks,
createJob,
} from "@playfulprogramming/bullmq";
import { createImageUrl } from "../../utils.ts";

const PostImageRequestSchema = Type.Object(
{
Expand Down Expand Up @@ -49,13 +49,10 @@ const PostImagesResponseSchema = Type.Object(
function mapPostImages(
result: PostImageOutput,
): Static<typeof PostImagesResponseSchema> {
const s3PublicUrl = `${env.S3_PUBLIC_URL}/${env.S3_BUCKET}/`;
return {
banner: result.bannerKey
? new URL(result.bannerKey, s3PublicUrl).toString()
: undefined,
banner: result.bannerKey ? createImageUrl(result.bannerKey) : undefined,
linkPreview: result.linkPreviewKey
? new URL(result.linkPreviewKey, s3PublicUrl).toString()
? createImageUrl(result.linkPreviewKey)
: undefined,
};
}
Expand Down
11 changes: 3 additions & 8 deletions apps/api/src/routes/tasks/url-metadata.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { FastifyPluginAsync } from "fastify";
import { env } from "@playfulprogramming/common";
import { db } from "@playfulprogramming/db";
import { Type, type Static } from "typebox";
import {
Expand All @@ -8,6 +7,7 @@ import {
UrlMetadataInputSchema,
createJob,
} from "@playfulprogramming/bullmq";
import { createImageUrl } from "../../utils.ts";

type UrlMetadataDbResult = NonNullable<
Awaited<ReturnType<typeof db.query.urlMetadata.findFirst>>
Expand Down Expand Up @@ -106,11 +106,6 @@ const UrlMetadataResponseSchema = Type.Object(
},
);

function mapObjectKey(key: string): string {
const s3PublicUrl = `${env.S3_PUBLIC_URL}/${env.S3_BUCKET}/`;
return new URL(key, s3PublicUrl).toString();
}

function mapImageData(
key: string | null,
width: number | null,
Expand All @@ -119,7 +114,7 @@ function mapImageData(
): Static<typeof ImageSchema> | undefined {
if (!key) return undefined;
return {
src: mapObjectKey(key),
src: createImageUrl(key),
width: width || undefined,
height: height || undefined,
altText: altText || undefined,
Expand All @@ -143,7 +138,7 @@ async function mapEmbedGist(
description: gist.description || undefined,
files: gistFiles.map((file) => ({
filename: file.filename,
contentUrl: mapObjectKey(file.contentKey),
contentUrl: createImageUrl(file.contentKey),
language: file.language,
})),
};
Expand Down
16 changes: 16 additions & 0 deletions apps/api/src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { env } from "@playfulprogramming/common";

/** Removes leading and trailing slashes from a string. */
function trimSlashes(input: string): string {
return input.replace(/^\/+|\/+$/g, "");
}

const S3_BASE_URL = `${trimSlashes(env.S3_PUBLIC_URL)}/${trimSlashes(env.S3_BUCKET)}/`;
/**
* Constructs a full S3 image URL from a relative path.
* @param path The relative path to the image.
* @returns The absolute URL to the image.
*/
export function createImageUrl(path: string): string {
return new URL(trimSlashes(path), S3_BASE_URL).toString();
}