realworld-hono-drizzle
Version:
A RealWorld backend built with Hono and Drizzle
1 lines • 60.2 kB
Source Map (JSON)
{"version":3,"sources":["../src/cli.ts","../src/factory.ts","../src/db/schema.ts","../src/modules/articles/articles.ts","../src/auth.ts","../src/modules/articles/am-i-following.ts","../src/modules/articles/schema.ts","../src/modules/profiles/schema.ts","../src/modules/articles/comments.ts","../src/modules/profiles/profiles.ts","../src/modules/tags/tags.ts","../src/modules/tags/schema.ts","../src/modules/users/user.ts","../src/modules/users/schema.ts","../src/modules/users/users.ts"],"sourcesContent":["#!/usr/bin/env node\nimport \"dotenv/config\";\nimport { randomBytes } from \"node:crypto\";\nimport { join } from \"node:path\";\nimport { serve } from \"@hono/node-server\";\nimport { drizzle } from \"drizzle-orm/libsql\";\nimport { migrate } from \"drizzle-orm/libsql/migrator\";\nimport {\n\tnumber,\n\tobject,\n\toptional,\n\tparse,\n\tpipe,\n\tstring,\n\ttransform,\n} from \"valibot\";\n\nimport { factory } from \"./factory.js\";\n\nconst Environment = object({\n\tDATABASE_URL: optional(string(), \"file:local.db\"),\n\tJWT_SECRET: optional(string(), randomBytes(64).toString(\"base64url\")),\n\tPORT: pipe(optional(string(), \"3000\"), transform(Number.parseInt), number()),\n});\nconst env = parse(Environment, process.env);\n\nconst app = factory.createApp();\n\nconsole.log(`Server is running on http://localhost:${env.PORT}`);\n\nmigrate(drizzle(env.DATABASE_URL), {\n\tmigrationsFolder: join(import.meta.dirname, \"../src/db/migrations\"),\n}).then(() =>\n\tserve({\n\t\tfetch(request, httpBindings) {\n\t\t\treturn app.fetch(request, { ...env, ...httpBindings });\n\t\t},\n\t\tport: env.PORT,\n\t}),\n);\n","import { type LibSQLDatabase, drizzle } from \"drizzle-orm/libsql\";\nimport { createFactory } from \"hono/factory\";\n\nimport * as schema from \"./db/schema.js\";\nimport { articlesModule } from \"./modules/articles/articles.js\";\nimport { commentsModule } from \"./modules/articles/comments.js\";\nimport { profilesModule } from \"./modules/profiles/profiles.js\";\nimport { tagsModule } from \"./modules/tags/tags.js\";\nimport { userModule } from \"./modules/users/user.js\";\nimport { usersModule } from \"./modules/users/users.js\";\n\nexport interface ThisAppEnv {\n\tVariables: { db: LibSQLDatabase<typeof schema> };\n\tBindings: {\n\t\tDATABASE_URL: string;\n\t\tJWT_SECRET: string;\n\t};\n}\n\nexport const factory = createFactory<ThisAppEnv>({\n\tinitApp(app) {\n\t\tapp.use(async (c, next) => {\n\t\t\tconst db = drizzle(c.env.DATABASE_URL, { schema });\n\t\t\tc.set(\"db\", db);\n\t\t\tawait next();\n\t\t});\n\n\t\tapp.route(\"/api/users\", usersModule);\n\t\tapp.route(\"/api/user\", userModule);\n\t\tapp.route(\"/api/profiles\", profilesModule);\n\t\tapp.route(\"/api/articles\", articlesModule);\n\t\tapp.route(\"/api/articles\", commentsModule);\n\t\tapp.route(\"/api/tags\", tagsModule);\n\t},\n});\n","import { relations, sql } from \"drizzle-orm\";\nimport {\n\tcustomType,\n\tint,\n\tprimaryKey,\n\tsqliteTable,\n\ttext,\n} from \"drizzle-orm/sqlite-core\";\n\nconst date = customType<{\n\tdata: string;\n\tdriverData: string;\n}>({\n\tdataType() {\n\t\treturn \"text\";\n\t},\n\tfromDriver(value: string): string {\n\t\tconst [date, time] = value.split(\" \");\n\t\treturn `${date}T${time}.000Z`;\n\t},\n});\n\nexport const usersTable = sqliteTable(\"users\", {\n\tid: int().primaryKey({ autoIncrement: true }),\n\temail: text().notNull().unique(),\n\tusername: text().notNull().unique(),\n\tbio: text(),\n\timage: text(),\n\tpasswordHash: text().notNull(),\n});\n\nexport const userFollowTable = sqliteTable(\n\t\"user_follow\",\n\t{\n\t\tfollowerId: int()\n\t\t\t.notNull()\n\t\t\t.references(() => usersTable.id, { onDelete: \"cascade\" }),\n\t\tfollowedId: int()\n\t\t\t.notNull()\n\t\t\t.references(() => usersTable.id, { onDelete: \"cascade\" }),\n\t},\n\t(t) => [primaryKey({ columns: [t.followerId, t.followedId] })],\n);\n\nexport const userFollowRelations = relations(userFollowTable, ({ one }) => ({\n\tfollower: one(usersTable, {\n\t\tfields: [userFollowTable.followerId],\n\t\treferences: [usersTable.id],\n\t}),\n\tfollowed: one(usersTable, {\n\t\tfields: [userFollowTable.followedId],\n\t\treferences: [usersTable.id],\n\t}),\n}));\n\nexport const tagsTable = sqliteTable(\"tags\", {\n\ttag: text().notNull().unique(),\n});\n\nexport const articlesTable = sqliteTable(\"articles\", {\n\tslug: text().primaryKey(),\n\ttitle: text().notNull(),\n\tdescription: text().notNull(),\n\tbody: text().notNull(),\n\tcreatedAt: date().notNull().default(sql`(CURRENT_TIMESTAMP)`),\n\tupdatedAt: date().notNull().default(sql`(CURRENT_TIMESTAMP)`),\n\tauthorId: int()\n\t\t.notNull()\n\t\t.references(() => usersTable.id, { onDelete: \"cascade\" }),\n});\n\nexport const commentsTable = sqliteTable(\"comments\", {\n\tid: int().primaryKey({ autoIncrement: true }),\n\tcreatedAt: date().notNull().default(sql`(CURRENT_TIMESTAMP)`),\n\tupdatedAt: date().notNull().default(sql`(CURRENT_TIMESTAMP)`),\n\tbody: text().notNull(),\n\tarticleSlug: text()\n\t\t.notNull()\n\t\t.references(() => articlesTable.slug, {\n\t\t\tonDelete: \"cascade\",\n\t\t\tonUpdate: \"cascade\",\n\t\t}),\n\tauthorId: int()\n\t\t.notNull()\n\t\t.references(() => usersTable.id, { onDelete: \"cascade\" }),\n});\n\nexport const articleTagTable = sqliteTable(\n\t\"article_tag\",\n\t{\n\t\tarticleSlug: text()\n\t\t\t.notNull()\n\t\t\t.references(() => articlesTable.slug, {\n\t\t\t\tonDelete: \"cascade\",\n\t\t\t\tonUpdate: \"cascade\",\n\t\t\t}),\n\t\ttag: text()\n\t\t\t.notNull()\n\t\t\t.references(() => tagsTable.tag, { onDelete: \"cascade\" }),\n\t},\n\t(t) => [primaryKey({ columns: [t.articleSlug, t.tag] })],\n);\n\nexport const articleFavoriteTable = sqliteTable(\n\t\"article_favorite\",\n\t{\n\t\tarticleSlug: text()\n\t\t\t.notNull()\n\t\t\t.references(() => articlesTable.slug, {\n\t\t\t\tonDelete: \"cascade\",\n\t\t\t\tonUpdate: \"cascade\",\n\t\t\t}),\n\t\tuserId: int()\n\t\t\t.notNull()\n\t\t\t.references(() => usersTable.id, { onDelete: \"cascade\" }),\n\t},\n\t(t) => [primaryKey({ columns: [t.articleSlug, t.userId] })],\n);\n\nexport const articleRelations = relations(articlesTable, ({ one, many }) => ({\n\tauthor: one(usersTable, {\n\t\tfields: [articlesTable.authorId],\n\t\treferences: [usersTable.id],\n\t}),\n\ttagList: many(articleTagTable),\n\tcommentRelations: many(commentsTable),\n}));\n\nexport const tagRelations = relations(tagsTable, ({ many }) => ({\n\tarticles: many(articleTagTable),\n}));\n\nexport const articleTagRelations = relations(articleTagTable, ({ one }) => ({\n\tarticle: one(articlesTable, {\n\t\tfields: [articleTagTable.articleSlug],\n\t\treferences: [articlesTable.slug],\n\t}),\n\ttag: one(tagsTable, {\n\t\tfields: [articleTagTable.tag],\n\t\treferences: [tagsTable.tag],\n\t}),\n}));\n\nexport const commentRelations = relations(commentsTable, ({ one }) => ({\n\tarticle: one(articlesTable, {\n\t\tfields: [commentsTable.articleSlug],\n\t\treferences: [articlesTable.slug],\n\t}),\n}));\n","import { vValidator } from \"@hono/valibot-validator\";\nimport slugify from \"@sindresorhus/slugify\";\nimport {\n\tand,\n\tcountDistinct,\n\tdesc,\n\teq,\n\texists,\n\tgetTableColumns,\n\tsql,\n} from \"drizzle-orm\";\nimport type { LibSQLDatabase } from \"drizzle-orm/libsql\";\nimport type { SQLiteColumn } from \"drizzle-orm/sqlite-core\";\nimport { Hono } from \"hono\";\nimport { decode } from \"hono/jwt\";\nimport { type InferOutput, array, parse, string } from \"valibot\";\n\nimport { JwtClaims, exposeToken, jwtAuth } from \"../../auth.js\";\nimport type * as schema from \"../../db/schema.js\";\nimport {\n\tarticleFavoriteTable,\n\tarticleTagTable,\n\tarticlesTable,\n\ttagsTable,\n\tuserFollowTable,\n\tusersTable,\n} from \"../../db/schema.js\";\nimport type { ThisAppEnv } from \"../../factory.js\";\nimport { amIFollowing } from \"./am-i-following.js\";\nimport {\n\tArticleToCreate,\n\tMultipleArticlesResponse,\n\tSingleArticleResponse,\n\tUpdatedArticle,\n} from \"./schema.js\";\n\nexport const articlesModule = new Hono<ThisAppEnv>();\n\nconst TagList = array(string());\n\n/** Subquery to include the `favorited` field on an article. */\nfunction isFavorited({\n\tdb,\n\tarticleSlug,\n\tme,\n}: {\n\tdb: LibSQLDatabase<typeof schema>;\n\tarticleSlug: SQLiteColumn;\n\tme: number;\n}) {\n\treturn exists(\n\t\tdb\n\t\t\t.select({ exists: sql`1` })\n\t\t\t.from(articleFavoriteTable)\n\t\t\t.where(\n\t\t\t\tand(\n\t\t\t\t\teq(articleFavoriteTable.articleSlug, articleSlug),\n\t\t\t\t\teq(articleFavoriteTable.userId, me),\n\t\t\t\t),\n\t\t\t),\n\t);\n}\n\nasync function findArticle(\n\tdb: LibSQLDatabase<typeof schema>,\n\tslug: string,\n\tself: InferOutput<typeof JwtClaims> | null,\n) {\n\tconst [article] = await db\n\t\t.select({\n\t\t\t...getTableColumns(articlesTable),\n\t\t\tfavorited: (self === null\n\t\t\t\t? sql<number>`0`\n\t\t\t\t: isFavorited({ db, articleSlug: articlesTable.slug, me: self.id })\n\t\t\t).mapWith(Boolean),\n\t\t\tfavoritesCount: countDistinct(articleFavoriteTable.userId).as(\n\t\t\t\t\"favoritesCount\",\n\t\t\t),\n\t\t\ttagList:\n\t\t\t\tsql<string>`json_group_array(DISTINCT ${articleTagTable.tag}) filter (where ${articleTagTable.tag} is not null)`.mapWith(\n\t\t\t\t\t(tagList) => parse(TagList, JSON.parse(tagList)),\n\t\t\t\t),\n\t\t\tauthor: {\n\t\t\t\tusername: usersTable.username,\n\t\t\t\tbio: usersTable.bio,\n\t\t\t\timage: usersTable.image,\n\t\t\t\tfollowing: (self === null\n\t\t\t\t\t? sql<number>`0`\n\t\t\t\t\t: amIFollowing({ db, them: articlesTable.authorId, me: self.id })\n\t\t\t\t).mapWith(Boolean),\n\t\t\t},\n\t\t})\n\t\t.from(articlesTable)\n\t\t.leftJoin(\n\t\t\tarticleFavoriteTable,\n\t\t\teq(articlesTable.slug, articleFavoriteTable.articleSlug),\n\t\t)\n\t\t.leftJoin(\n\t\t\tarticleTagTable,\n\t\t\teq(articlesTable.slug, articleTagTable.articleSlug),\n\t\t)\n\t\t.innerJoin(usersTable, eq(articlesTable.authorId, usersTable.id))\n\t\t.where(eq(articlesTable.slug, slug))\n\t\t.groupBy(articlesTable.slug);\n\n\treturn article;\n}\n\narticlesModule.get(\"/\", exposeToken, async (c) => {\n\tconst db = c.get(\"db\");\n\tconst token = c.get(\"token\");\n\tconst self =\n\t\ttoken !== undefined ? parse(JwtClaims, decode(token).payload) : null;\n\n\tconst tagFilter = c.req.query(\"tag\");\n\tconst authorFilter = c.req.query(\"author\");\n\tconst favoritedFilter = c.req.query(\"favorited\");\n\tconst limit = Number(c.req.query(\"limit\") ?? 20);\n\tconst offset = Number(c.req.query(\"offset\") ?? 0);\n\n\tconst {\n\t\tbody: _body,\n\t\tauthorId: _authorId,\n\t\t...desiredColumns\n\t} = getTableColumns(articlesTable);\n\n\tconst slugsWithTagFilter = tagFilter\n\t\t? db\n\t\t\t\t.select({ slug: articleTagTable.articleSlug })\n\t\t\t\t.from(articleTagTable)\n\t\t\t\t.where(eq(articleTagTable.tag, tagFilter))\n\t\t\t\t.as(\"slugsWithTagFilter\")\n\t\t: null;\n\tconst slugsWithFavoritedFilter = favoritedFilter\n\t\t? db\n\t\t\t\t.select({ slug: articleFavoriteTable.articleSlug })\n\t\t\t\t.from(articleFavoriteTable)\n\t\t\t\t.innerJoin(usersTable, eq(articleFavoriteTable.userId, usersTable.id))\n\t\t\t\t.where(eq(usersTable.username, favoritedFilter))\n\t\t\t\t.as(\"slugsWithFavoritedFilter\")\n\t\t: null;\n\n\tconst articles = await db\n\t\t.select({\n\t\t\t...desiredColumns,\n\t\t\tfavorited: (self === null\n\t\t\t\t? sql<number>`0`\n\t\t\t\t: isFavorited({ db, articleSlug: articlesTable.slug, me: self.id })\n\t\t\t).mapWith(Boolean),\n\t\t\tfavoritesCount: countDistinct(articleFavoriteTable.userId).as(\n\t\t\t\t\"favoritesCount\",\n\t\t\t),\n\t\t\ttagList:\n\t\t\t\tsql<string>`json_group_array(DISTINCT ${articleTagTable.tag}) filter (where ${articleTagTable.tag} is not null)`.mapWith(\n\t\t\t\t\t(tagList) => parse(TagList, JSON.parse(tagList)),\n\t\t\t\t),\n\t\t\tauthor: {\n\t\t\t\tusername: usersTable.username,\n\t\t\t\tbio: usersTable.bio,\n\t\t\t\timage: usersTable.image,\n\t\t\t\tfollowing: (self === null\n\t\t\t\t\t? sql<number>`0`\n\t\t\t\t\t: amIFollowing({ db, them: articlesTable.authorId, me: self.id })\n\t\t\t\t).mapWith(Boolean),\n\t\t\t},\n\t\t})\n\t\t.from(articlesTable)\n\t\t.leftJoin(\n\t\t\tarticleFavoriteTable,\n\t\t\teq(articlesTable.slug, articleFavoriteTable.articleSlug),\n\t\t)\n\t\t.leftJoin(\n\t\t\tarticleTagTable,\n\t\t\teq(articlesTable.slug, articleTagTable.articleSlug),\n\t\t)\n\t\t.innerJoin(usersTable, eq(articlesTable.authorId, usersTable.id))\n\t\t.where(\n\t\t\tand(\n\t\t\t\tslugsWithTagFilter\n\t\t\t\t\t? exists(\n\t\t\t\t\t\t\tdb\n\t\t\t\t\t\t\t\t.select()\n\t\t\t\t\t\t\t\t.from(slugsWithTagFilter)\n\t\t\t\t\t\t\t\t.where(eq(slugsWithTagFilter.slug, articlesTable.slug)),\n\t\t\t\t\t\t)\n\t\t\t\t\t: undefined,\n\t\t\t\tauthorFilter ? eq(usersTable.username, authorFilter) : undefined,\n\t\t\t\tslugsWithFavoritedFilter\n\t\t\t\t\t? exists(\n\t\t\t\t\t\t\tdb\n\t\t\t\t\t\t\t\t.select()\n\t\t\t\t\t\t\t\t.from(slugsWithFavoritedFilter)\n\t\t\t\t\t\t\t\t.where(eq(slugsWithFavoritedFilter.slug, articlesTable.slug)),\n\t\t\t\t\t\t)\n\t\t\t\t\t: undefined,\n\t\t\t),\n\t\t)\n\t\t.limit(limit)\n\t\t.offset(offset)\n\t\t.groupBy(articlesTable.slug)\n\t\t.orderBy(desc(articlesTable.createdAt));\n\n\tconst totalCountResult = await db\n\t\t.select({ count: countDistinct(articlesTable.slug) })\n\t\t.from(articlesTable)\n\t\t.leftJoin(\n\t\t\tarticleFavoriteTable,\n\t\t\teq(articlesTable.slug, articleFavoriteTable.articleSlug),\n\t\t)\n\t\t.leftJoin(\n\t\t\tarticleTagTable,\n\t\t\teq(articlesTable.slug, articleTagTable.articleSlug),\n\t\t)\n\t\t.innerJoin(usersTable, eq(articlesTable.authorId, usersTable.id))\n\t\t.where(\n\t\t\tand(\n\t\t\t\tslugsWithTagFilter\n\t\t\t\t\t? exists(\n\t\t\t\t\t\t\tdb\n\t\t\t\t\t\t\t\t.select()\n\t\t\t\t\t\t\t\t.from(slugsWithTagFilter)\n\t\t\t\t\t\t\t\t.where(eq(slugsWithTagFilter.slug, articlesTable.slug)),\n\t\t\t\t\t\t)\n\t\t\t\t\t: undefined,\n\t\t\t\tauthorFilter ? eq(usersTable.username, authorFilter) : undefined,\n\t\t\t\tslugsWithFavoritedFilter\n\t\t\t\t\t? exists(\n\t\t\t\t\t\t\tdb\n\t\t\t\t\t\t\t\t.select()\n\t\t\t\t\t\t\t\t.from(slugsWithFavoritedFilter)\n\t\t\t\t\t\t\t\t.where(eq(slugsWithFavoritedFilter.slug, articlesTable.slug)),\n\t\t\t\t\t\t)\n\t\t\t\t\t: undefined,\n\t\t\t),\n\t\t);\n\n\treturn c.json(\n\t\tparse(MultipleArticlesResponse, {\n\t\t\tarticles,\n\t\t\tarticlesCount: totalCountResult[0]?.count ?? 0,\n\t\t}),\n\t);\n});\n\narticlesModule.get(\"/feed\", jwtAuth, async (c) => {\n\tconst db = c.get(\"db\");\n\tconst self = c.get(\"jwtPayload\");\n\n\tconst limit = Number(c.req.query(\"limit\") ?? 20);\n\tconst offset = Number(c.req.query(\"offset\") ?? 0);\n\n\tconst {\n\t\tbody: _body,\n\t\tauthorId: _authorId,\n\t\t...desiredColumns\n\t} = getTableColumns(articlesTable);\n\n\tconst articles = await db\n\t\t.select({\n\t\t\t...desiredColumns,\n\t\t\tfavorited: (self === null\n\t\t\t\t? sql<number>`0`\n\t\t\t\t: isFavorited({ db, articleSlug: articlesTable.slug, me: self.id })\n\t\t\t).mapWith(Boolean),\n\t\t\tfavoritesCount: countDistinct(articleFavoriteTable.userId).as(\n\t\t\t\t\"favoritesCount\",\n\t\t\t),\n\t\t\ttagList:\n\t\t\t\tsql<string>`json_group_array(DISTINCT ${articleTagTable.tag}) filter (where ${articleTagTable.tag} is not null)`.mapWith(\n\t\t\t\t\t(tagList) => parse(TagList, JSON.parse(tagList)),\n\t\t\t\t),\n\t\t\tauthor: {\n\t\t\t\tusername: usersTable.username,\n\t\t\t\tbio: usersTable.bio,\n\t\t\t\timage: usersTable.image,\n\t\t\t\tfollowing: (self === null\n\t\t\t\t\t? sql<number>`0`\n\t\t\t\t\t: amIFollowing({ db, them: articlesTable.authorId, me: self.id })\n\t\t\t\t).mapWith(Boolean),\n\t\t\t},\n\t\t})\n\t\t.from(articlesTable)\n\t\t.leftJoin(\n\t\t\tarticleFavoriteTable,\n\t\t\teq(articlesTable.slug, articleFavoriteTable.articleSlug),\n\t\t)\n\t\t.leftJoin(\n\t\t\tarticleTagTable,\n\t\t\teq(articlesTable.slug, articleTagTable.articleSlug),\n\t\t)\n\t\t.innerJoin(usersTable, eq(articlesTable.authorId, usersTable.id))\n\t\t.rightJoin(\n\t\t\tuserFollowTable,\n\t\t\teq(userFollowTable.followedId, articlesTable.authorId),\n\t\t)\n\t\t.where(eq(userFollowTable.followerId, self.id))\n\t\t.limit(limit)\n\t\t.offset(offset)\n\t\t.groupBy(articlesTable.slug)\n\t\t.orderBy(desc(articlesTable.createdAt));\n\n\tconst totalCountResult = await db\n\t\t.select({ count: countDistinct(articlesTable.slug) })\n\t\t.from(articlesTable)\n\t\t.leftJoin(\n\t\t\tarticleFavoriteTable,\n\t\t\teq(articlesTable.slug, articleFavoriteTable.articleSlug),\n\t\t)\n\t\t.leftJoin(\n\t\t\tarticleTagTable,\n\t\t\teq(articlesTable.slug, articleTagTable.articleSlug),\n\t\t)\n\t\t.innerJoin(usersTable, eq(articlesTable.authorId, usersTable.id))\n\t\t.rightJoin(\n\t\t\tuserFollowTable,\n\t\t\teq(userFollowTable.followedId, articlesTable.authorId),\n\t\t)\n\t\t.where(eq(userFollowTable.followerId, self.id));\n\n\treturn c.json(\n\t\tparse(MultipleArticlesResponse, {\n\t\t\tarticles,\n\t\t\tarticlesCount: totalCountResult[0]?.count ?? 0,\n\t\t}),\n\t);\n});\n\narticlesModule.get(\"/:slug\", exposeToken, async (c) => {\n\tconst db = c.get(\"db\");\n\tconst token = c.get(\"token\");\n\tconst self =\n\t\ttoken !== undefined ? parse(JwtClaims, decode(token).payload) : null;\n\n\tconst slug = c.req.param(\"slug\");\n\n\tconst article = await findArticle(db, slug, self);\n\n\tif (article === undefined) {\n\t\treturn c.notFound();\n\t}\n\n\treturn c.json(parse(SingleArticleResponse, { article }));\n});\n\narticlesModule.post(\n\t\"/\",\n\tjwtAuth,\n\tvValidator(\"json\", ArticleToCreate),\n\tasync (c) => {\n\t\tconst db = c.get(\"db\");\n\t\tconst self = c.get(\"jwtPayload\");\n\n\t\tconst { tagList, ...articlePayload } = c.req.valid(\"json\").article;\n\t\tconst slug = slugify(articlePayload.title);\n\n\t\tawait db.insert(articlesTable).values({\n\t\t\tslug,\n\t\t\t...articlePayload,\n\t\t\tauthorId: self.id,\n\t\t});\n\n\t\tif (tagList !== undefined) {\n\t\t\tawait db.insert(tagsTable).values(tagList.map((tag) => ({ tag })));\n\t\t\tawait db\n\t\t\t\t.insert(articleTagTable)\n\t\t\t\t.values(tagList.map((tag) => ({ articleSlug: slug, tag })));\n\t\t}\n\n\t\tconst article = await findArticle(db, slug, self);\n\n\t\treturn c.json(parse(SingleArticleResponse, { article }));\n\t},\n);\n\narticlesModule.put(\n\t\"/:slug\",\n\tjwtAuth,\n\tvValidator(\"json\", UpdatedArticle),\n\tasync (c) => {\n\t\tconst db = c.get(\"db\");\n\t\tconst self = c.get(\"jwtPayload\");\n\n\t\tlet slug = c.req.param(\"slug\");\n\t\tconst { article: articlePayload } = c.req.valid(\"json\");\n\n\t\tconst [articleOwnership] = await db\n\t\t\t.select({ isOwned: eq(articlesTable.authorId, self.id) })\n\t\t\t.from(articlesTable)\n\t\t\t.where(eq(articlesTable.slug, slug));\n\n\t\tif (articleOwnership === undefined) {\n\t\t\treturn c.notFound();\n\t\t}\n\t\tif (!articleOwnership.isOwned) {\n\t\t\treturn new Response(\"Forbidden\", { status: 403 });\n\t\t}\n\n\t\tawait db\n\t\t\t.update(articlesTable)\n\t\t\t.set(articlePayload)\n\t\t\t.where(eq(articlesTable.slug, slug));\n\n\t\tif (articlePayload.title !== undefined) {\n\t\t\tconst newSlug = slugify(articlePayload.title);\n\t\t\tawait db\n\t\t\t\t.update(articlesTable)\n\t\t\t\t.set({ slug: newSlug })\n\t\t\t\t.where(eq(articlesTable.slug, slug));\n\t\t\tslug = newSlug;\n\t\t}\n\n\t\tconst article = await findArticle(db, slug, self);\n\n\t\treturn c.json(parse(SingleArticleResponse, { article }));\n\t},\n);\n\narticlesModule.delete(\"/:slug\", jwtAuth, async (c) => {\n\tconst db = c.get(\"db\");\n\tconst self = c.get(\"jwtPayload\");\n\n\tconst slug = c.req.param(\"slug\");\n\n\tconst [articleOwnership] = await db\n\t\t.select({ isOwned: eq(articlesTable.authorId, self.id) })\n\t\t.from(articlesTable)\n\t\t.where(eq(articlesTable.slug, slug));\n\n\tif (articleOwnership === undefined) {\n\t\treturn c.notFound();\n\t}\n\tif (!articleOwnership.isOwned) {\n\t\treturn new Response(\"Forbidden\", { status: 403 });\n\t}\n\n\tawait db.delete(articlesTable).where(eq(articlesTable.slug, slug));\n\n\treturn new Response(null, { status: 204 });\n});\n\narticlesModule.post(\"/:slug/favorite\", jwtAuth, async (c) => {\n\tconst db = c.get(\"db\");\n\tconst self = c.get(\"jwtPayload\");\n\n\tconst slug = c.req.param(\"slug\");\n\n\tconst [articleExists] = await db\n\t\t.select({ exists: sql`1` })\n\t\t.from(articlesTable)\n\t\t.where(eq(articlesTable.slug, slug));\n\n\tif (articleExists === undefined) {\n\t\treturn c.notFound();\n\t}\n\n\tawait db\n\t\t.insert(articleFavoriteTable)\n\t\t.values({\n\t\t\tarticleSlug: slug,\n\t\t\tuserId: self.id,\n\t\t})\n\t\t.onConflictDoNothing();\n\n\tconst updatedArticle = await findArticle(db, slug, self);\n\n\treturn c.json(parse(SingleArticleResponse, { article: updatedArticle }));\n});\n\narticlesModule.delete(\"/:slug/favorite\", jwtAuth, async (c) => {\n\tconst db = c.get(\"db\");\n\tconst self = c.get(\"jwtPayload\");\n\n\tconst slug = c.req.param(\"slug\");\n\n\tconst [articleExists] = await db\n\t\t.select({ exists: sql`1` })\n\t\t.from(articlesTable)\n\t\t.where(eq(articlesTable.slug, slug));\n\n\tif (articleExists === undefined) {\n\t\treturn c.notFound();\n\t}\n\n\tawait db\n\t\t.delete(articleFavoriteTable)\n\t\t.where(\n\t\t\tand(\n\t\t\t\teq(articleFavoriteTable.articleSlug, slug),\n\t\t\t\teq(articleFavoriteTable.userId, self.id),\n\t\t\t),\n\t\t);\n\n\tconst updatedArticle = await findArticle(db, slug, self);\n\n\treturn c.json(parse(SingleArticleResponse, { article: updatedArticle }));\n});\n","import { createMiddleware } from \"hono/factory\";\nimport { jwt } from \"hono/jwt\";\nimport { type InferOutput, number, object } from \"valibot\";\n\nimport type { ThisAppEnv } from \"./factory.js\";\n\nexport const JwtClaims = object({\n\tid: number(),\n});\n\nexport const jwtAuth = createMiddleware<{\n\tVariables: { jwtPayload: InferOutput<typeof JwtClaims> };\n\tBindings: ThisAppEnv[\"Bindings\"];\n}>((c, next) => {\n\tconst jwtMiddleware = jwt({\n\t\tsecret: c.env.JWT_SECRET,\n\t});\n\treturn jwtMiddleware(c, next);\n});\n\nexport const exposeToken = createMiddleware<{\n\tVariables: {\n\t\ttoken: string | undefined;\n\t};\n}>(async (c, next) => {\n\tconst token = c.req.header(\"Authorization\")?.split(\" \")[1];\n\n\tc.set(\"token\", token);\n\tawait next();\n});\n","import { and, eq, exists, sql } from \"drizzle-orm\";\nimport type { LibSQLDatabase } from \"drizzle-orm/libsql\";\nimport type { SQLiteColumn } from \"drizzle-orm/sqlite-core\";\n\nimport type * as schema from \"../../db/schema.js\";\nimport { userFollowTable } from \"../../db/schema.js\";\n\n/** Subquery to include the `following` field on a user object. */\nexport function amIFollowing({\n\tdb,\n\tme,\n\tthem,\n}: { db: LibSQLDatabase<typeof schema>; them: SQLiteColumn; me: number }) {\n\treturn exists(\n\t\tdb\n\t\t\t.select({ exists: sql`1` })\n\t\t\t.from(userFollowTable)\n\t\t\t.where(\n\t\t\t\tand(\n\t\t\t\t\teq(userFollowTable.followerId, me),\n\t\t\t\t\teq(userFollowTable.followedId, them),\n\t\t\t\t),\n\t\t\t),\n\t);\n}\n","import {\n\tarray,\n\tboolean,\n\tnumber,\n\tobject,\n\tomit,\n\toptional,\n\tpartial,\n\tstring,\n} from \"valibot\";\nimport { Profile } from \"../profiles/schema.js\";\n\nconst Article = object({\n\tslug: string(),\n\ttitle: string(),\n\tdescription: string(),\n\tbody: string(),\n\ttagList: array(string()),\n\tcreatedAt: string(),\n\tupdatedAt: string(),\n\tfavorited: boolean(),\n\tfavoritesCount: number(),\n\tauthor: Profile,\n});\n\nconst Comment = object({\n\tid: number(),\n\tcreatedAt: string(),\n\tupdatedAt: string(),\n\tbody: string(),\n\tauthor: Profile,\n});\n\nexport const SingleArticleResponse = object({\n\tarticle: Article,\n});\n\nexport const MultipleArticlesResponse = object({\n\tarticles: array(omit(Article, [\"body\"])),\n\tarticlesCount: number(),\n});\n\nexport const ArticleToCreate = object({\n\tarticle: object({\n\t\ttitle: string(),\n\t\tdescription: string(),\n\t\tbody: string(),\n\t\ttagList: optional(array(string())),\n\t}),\n});\n\nexport const UpdatedArticle = object({\n\tarticle: partial(\n\t\tobject({\n\t\t\ttitle: string(),\n\t\t\tdescription: string(),\n\t\t\tbody: string(),\n\t\t}),\n\t),\n});\n\nexport const SingleCommentResponse = object({\n\tcomment: Comment,\n});\n\nexport const MultipleCommentsResponse = object({\n\tcomments: array(Comment),\n});\n\nexport const CommentToCreate = object({\n\tcomment: object({\n\t\tbody: string(),\n\t}),\n});\n","import { boolean, nullable, object, string } from \"valibot\";\n\nexport const Profile = object({\n\tusername: string(),\n\tbio: nullable(string()),\n\timage: nullable(string()),\n\tfollowing: boolean(),\n});\n\nexport const ProfileResponse = object({\n\tprofile: Profile,\n});\n","import { and, eq, getTableColumns, sql } from \"drizzle-orm\";\nimport { Hono } from \"hono\";\nimport { decode } from \"hono/jwt\";\nimport { parse } from \"valibot\";\n\nimport { vValidator } from \"@hono/valibot-validator\";\nimport { JwtClaims, exposeToken, jwtAuth } from \"../../auth.js\";\nimport { articlesTable, commentsTable, usersTable } from \"../../db/schema.js\";\nimport type { ThisAppEnv } from \"../../factory.js\";\nimport { amIFollowing } from \"./am-i-following.js\";\nimport {\n\tCommentToCreate,\n\tMultipleCommentsResponse,\n\tSingleCommentResponse,\n} from \"./schema.js\";\n\nexport const commentsModule = new Hono<ThisAppEnv>();\n\ncommentsModule.get(\"/:slug/comments\", exposeToken, async (c) => {\n\tconst db = c.get(\"db\");\n\tconst token = c.get(\"token\");\n\tconst self =\n\t\ttoken !== undefined ? parse(JwtClaims, decode(token).payload) : null;\n\n\tconst slug = c.req.param(\"slug\");\n\n\tconst [articleExists] = await db\n\t\t.select({ exists: sql`1` })\n\t\t.from(articlesTable)\n\t\t.where(eq(articlesTable.slug, slug));\n\n\tif (!articleExists) {\n\t\treturn c.notFound();\n\t}\n\n\tconst {\n\t\tauthorId: _authorId,\n\t\tarticleSlug: _articleSlug,\n\t\t...desiredColumns\n\t} = getTableColumns(commentsTable);\n\tconst comments = await db\n\t\t.select({\n\t\t\t...desiredColumns,\n\t\t\tauthor: {\n\t\t\t\tusername: usersTable.username,\n\t\t\t\tbio: usersTable.bio,\n\t\t\t\timage: usersTable.image,\n\t\t\t\tfollowing: (self === null\n\t\t\t\t\t? sql<number>`0`\n\t\t\t\t\t: amIFollowing({ db, them: commentsTable.authorId, me: self.id })\n\t\t\t\t).mapWith(Boolean),\n\t\t\t},\n\t\t})\n\t\t.from(commentsTable)\n\t\t.innerJoin(usersTable, eq(commentsTable.authorId, usersTable.id))\n\t\t.where(eq(commentsTable.articleSlug, slug));\n\n\treturn c.json(parse(MultipleCommentsResponse, { comments }));\n});\n\ncommentsModule.post(\n\t\"/:slug/comments\",\n\tjwtAuth,\n\tvValidator(\"json\", CommentToCreate),\n\tasync (c) => {\n\t\tconst db = c.get(\"db\");\n\t\tconst self = c.get(\"jwtPayload\");\n\n\t\tconst slug = c.req.param(\"slug\");\n\n\t\tconst [articleExists] = await db\n\t\t\t.select({ exists: sql`1` })\n\t\t\t.from(articlesTable)\n\t\t\t.where(eq(articlesTable.slug, slug));\n\n\t\tif (!articleExists) {\n\t\t\treturn c.notFound();\n\t\t}\n\n\t\tconst {\n\t\t\tauthorId: _authorId,\n\t\t\tarticleSlug: _articleSlug,\n\t\t\t...desiredColumns\n\t\t} = getTableColumns(commentsTable);\n\t\tconst commentPayload = c.req.valid(\"json\").comment;\n\t\tconst [addedComment] = await db\n\t\t\t.insert(commentsTable)\n\t\t\t.values([{ ...commentPayload, articleSlug: slug, authorId: self.id }])\n\t\t\t.returning(desiredColumns);\n\n\t\tif (addedComment === undefined) {\n\t\t\tthrow new Error(\"Failed to insert a comment\");\n\t\t}\n\n\t\tconst selfProfile = await db.query.usersTable.findFirst({\n\t\t\tcolumns: {\n\t\t\t\tusername: true,\n\t\t\t\tbio: true,\n\t\t\t\timage: true,\n\t\t\t},\n\t\t\twhere: eq(usersTable.id, self.id),\n\t\t});\n\n\t\treturn c.json(\n\t\t\tparse(SingleCommentResponse, {\n\t\t\t\tcomment: {\n\t\t\t\t\t...addedComment,\n\t\t\t\t\tauthor: { ...selfProfile, following: false },\n\t\t\t\t},\n\t\t\t}),\n\t\t);\n\t},\n);\n\ncommentsModule.delete(\"/:slug/comments/:id\", jwtAuth, async (c) => {\n\tconst db = c.get(\"db\");\n\tconst self = c.get(\"jwtPayload\");\n\n\tconst slug = c.req.param(\"slug\");\n\tconst id = Number.parseInt(c.req.param(\"id\"), 10);\n\n\tconst [commentOwnership] = await db\n\t\t.select({ isOwned: eq(commentsTable.authorId, self.id) })\n\t\t.from(commentsTable)\n\t\t.where(and(eq(commentsTable.id, id), eq(commentsTable.articleSlug, slug)));\n\n\tif (commentOwnership === undefined) {\n\t\treturn c.notFound();\n\t}\n\tif (!commentOwnership.isOwned) {\n\t\treturn new Response(\"Forbidden\", { status: 403 });\n\t}\n\n\tawait db.delete(commentsTable).where(eq(commentsTable.id, id));\n\n\treturn new Response(null, { status: 204 });\n});\n","import { and, eq } from \"drizzle-orm\";\nimport { Hono } from \"hono\";\nimport { parse } from \"valibot\";\n\nimport { decode } from \"hono/jwt\";\nimport { JwtClaims, exposeToken, jwtAuth } from \"../../auth.js\";\nimport { userFollowTable, usersTable } from \"../../db/schema.js\";\nimport type { ThisAppEnv } from \"../../factory.js\";\nimport { ProfileResponse } from \"./schema.js\";\n\nexport const profilesModule = new Hono<ThisAppEnv>();\n\nprofilesModule.get(\"/:username\", exposeToken, async (c) => {\n\tconst db = c.get(\"db\");\n\tconst token = c.get(\"token\");\n\tconst self =\n\t\ttoken !== undefined ? parse(JwtClaims, decode(token).payload) : null;\n\n\tconst user = await db.query.usersTable.findFirst({\n\t\twhere: eq(usersTable.username, c.req.param(\"username\")),\n\t});\n\n\tif (user === undefined) {\n\t\treturn c.notFound();\n\t}\n\n\tconst following =\n\t\tself !== null\n\t\t\t? (await db.query.userFollowTable.findFirst({\n\t\t\t\t\twhere: and(\n\t\t\t\t\t\teq(userFollowTable.followerId, self.id),\n\t\t\t\t\t\teq(userFollowTable.followedId, user.id),\n\t\t\t\t\t),\n\t\t\t\t})) !== undefined\n\t\t\t: false;\n\n\treturn c.json(parse(ProfileResponse, { profile: { ...user, following } }));\n});\n\nprofilesModule.post(\"/:username/follow\", jwtAuth, async (c) => {\n\tconst db = c.get(\"db\");\n\tconst self = c.get(\"jwtPayload\");\n\tconst userToFollow = await db.query.usersTable.findFirst({\n\t\twhere: eq(usersTable.username, c.req.param(\"username\")),\n\t});\n\n\tif (userToFollow === undefined) {\n\t\treturn c.notFound();\n\t}\n\n\tawait db.insert(userFollowTable).values({\n\t\tfollowerId: self.id,\n\t\tfollowedId: userToFollow.id,\n\t});\n\n\treturn c.json(\n\t\tparse(ProfileResponse, { profile: { ...userToFollow, following: true } }),\n\t);\n});\n\nprofilesModule.delete(\"/:username/follow\", jwtAuth, async (c) => {\n\tconst db = c.get(\"db\");\n\tconst self = c.get(\"jwtPayload\");\n\tconst userToUnfollow = await db.query.usersTable.findFirst({\n\t\twhere: eq(usersTable.username, c.req.param(\"username\")),\n\t});\n\n\tif (userToUnfollow === undefined) {\n\t\treturn c.notFound();\n\t}\n\n\tawait db\n\t\t.delete(userFollowTable)\n\t\t.where(\n\t\t\tand(\n\t\t\t\teq(userFollowTable.followerId, self.id),\n\t\t\t\teq(userFollowTable.followedId, userToUnfollow.id),\n\t\t\t),\n\t\t);\n\n\treturn c.json(\n\t\tparse(ProfileResponse, {\n\t\t\tprofile: { ...userToUnfollow, following: false },\n\t\t}),\n\t);\n});\n","import { Hono } from \"hono\";\nimport { parse } from \"valibot\";\n\nimport type { ThisAppEnv } from \"../../factory.js\";\nimport { ListOfTags } from \"./schema.js\";\n\nexport const tagsModule = new Hono<ThisAppEnv>();\n\ntagsModule.get(\"/\", async (c) => {\n\tconst db = c.get(\"db\");\n\tconst tags = await db.query.tagsTable.findMany();\n\n\treturn c.json(parse(ListOfTags, { tags: tags.map(({ tag }) => tag) }));\n});\n","import { array, object, string } from \"valibot\";\n\nexport const ListOfTags = object({\n\ttags: array(string()),\n});\n","import { vValidator } from \"@hono/valibot-validator\";\nimport { eq } from \"drizzle-orm\";\nimport { Hono } from \"hono\";\nimport { parse } from \"valibot\";\n\nimport { exposeToken, jwtAuth } from \"../../auth.js\";\nimport { usersTable } from \"../../db/schema.js\";\nimport type { ThisAppEnv } from \"../../factory.js\";\nimport { UpdatedDetails, UserResponse } from \"./schema.js\";\n\nexport const userModule = new Hono<ThisAppEnv>().use(jwtAuth).use(exposeToken);\n\nuserModule.get(\"/\", async (c) => {\n\tconst db = c.get(\"db\");\n\tconst self = c.get(\"jwtPayload\");\n\tconst user = await db.query.usersTable.findFirst({\n\t\twhere: eq(usersTable.id, self.id),\n\t});\n\n\tif (user === undefined) {\n\t\treturn c.notFound();\n\t}\n\n\treturn c.json(\n\t\tparse(UserResponse, { user: { ...user, token: c.get(\"token\") } }),\n\t);\n});\n\nuserModule.put(\"/\", vValidator(\"json\", UpdatedDetails), async (c) => {\n\tconst db = c.get(\"db\");\n\tconst self = c.get(\"jwtPayload\");\n\tconst user = await db.query.usersTable.findFirst({\n\t\twhere: eq(usersTable.id, self.id),\n\t});\n\n\tif (user === undefined) {\n\t\treturn c.notFound();\n\t}\n\n\tconst requestData = c.req.valid(\"json\");\n\tconst [updatedUser] = await db\n\t\t.update(usersTable)\n\t\t.set(requestData.user)\n\t\t.where(eq(usersTable.id, self.id))\n\t\t.returning();\n\n\treturn c.json(\n\t\tparse(UserResponse, { user: { ...updatedUser, token: c.get(\"token\") } }),\n\t);\n});\n","import { url, email, nullable, object, partial, pipe, string } from \"valibot\";\n\nexport const LoginCredentials = object({\n\tuser: object({\n\t\temail: pipe(string(), email()),\n\t\tpassword: string(),\n\t}),\n});\n\nexport const RegistrationDetails = object({\n\tuser: object({\n\t\tusername: string(),\n\t\temail: pipe(string(), email()),\n\t\tpassword: string(),\n\t}),\n});\n\nexport const UpdatedDetails = object({\n\tuser: partial(\n\t\tobject({\n\t\t\tusername: string(),\n\t\t\temail: pipe(string(), email()),\n\t\t\tpassword: string(),\n\t\t\tbio: nullable(string()),\n\t\t\timage: nullable(pipe(string(), url())),\n\t\t}),\n\t),\n});\n\nexport const UserResponse = object({\n\tuser: object({\n\t\temail: string(),\n\t\ttoken: string(),\n\t\tusername: string(),\n\t\tbio: nullable(string()),\n\t\timage: nullable(string()),\n\t}),\n});\n","import { vValidator } from \"@hono/valibot-validator\";\nimport bcrypt from \"bcryptjs\";\nimport { eq, or } from \"drizzle-orm\";\nimport { Hono } from \"hono\";\nimport { sign } from \"hono/jwt\";\nimport { parse } from \"valibot\";\n\nimport { JwtClaims } from \"../../auth.js\";\nimport { usersTable } from \"../../db/schema.js\";\nimport type { ThisAppEnv } from \"../../factory.js\";\nimport {\n\tLoginCredentials,\n\tRegistrationDetails,\n\tUserResponse,\n} from \"./schema.js\";\n\nexport const usersModule = new Hono<ThisAppEnv>();\n\nusersModule.post(\"/login\", vValidator(\"json\", LoginCredentials), async (c) => {\n\tconst db = c.get(\"db\");\n\tconst requestData = c.req.valid(\"json\");\n\tconst user = await db.query.usersTable.findFirst({\n\t\twhere: eq(usersTable.email, requestData.user.email),\n\t});\n\n\tconst isMatch =\n\t\tuser !== undefined &&\n\t\t(await bcrypt.compare(requestData.user.password, user.passwordHash));\n\n\tif (!isMatch) {\n\t\treturn c.json({ errors: { password: [\"invalid for this email\"] } }, 422);\n\t}\n\n\tconst token = await sign(parse(JwtClaims, user), c.env.JWT_SECRET);\n\n\treturn c.json(parse(UserResponse, { user: { ...user, token } }));\n});\n\nusersModule.post(\"/\", vValidator(\"json\", RegistrationDetails), async (c) => {\n\tconst db = c.get(\"db\");\n\tconst requestData = c.req.valid(\"json\");\n\n\tconst existingUser = await db.query.usersTable.findFirst({\n\t\twhere: or(\n\t\t\teq(usersTable.email, requestData.user.email),\n\t\t\teq(usersTable.username, requestData.user.username),\n\t\t),\n\t});\n\n\tif (existingUser?.email === requestData.user.email) {\n\t\treturn c.json({ errors: { email: [\"already in use\"] } }, 422);\n\t}\n\tif (existingUser?.username === requestData.user.username) {\n\t\treturn c.json({ errors: { username: [\"already in use\"] } }, 422);\n\t}\n\n\tconst passwordHash = await bcrypt.hash(requestData.user.password, 10);\n\n\tconst [user] = await db\n\t\t.insert(usersTable)\n\t\t.values({\n\t\t\temail: requestData.user.email,\n\t\t\tusername: requestData.user.username,\n\t\t\tpasswordHash,\n\t\t})\n\t\t.returning();\n\n\tconst token = await sign(parse(JwtClaims, user), c.env.JWT_SECRET);\n\n\treturn c.json(parse(UserResponse, { user: { ...user, token } }));\n});\n"],"mappings":"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