diff --git a/apps/web/app/api/public/[...route]/route.ts b/apps/web/app/api/public/[...route]/route.ts index ea62949..caafbee 100644 --- a/apps/web/app/api/public/[...route]/route.ts +++ b/apps/web/app/api/public/[...route]/route.ts @@ -3,38 +3,11 @@ import { createClient } from "@/lib/server/supabase"; import { logger } from "hono/logger"; import { prettyJSON } from "hono/pretty-json"; import { Hono } from "hono"; -import bcrypt from "bcrypt"; import { categories, postBySlug, posts, tags } from "./public-api.constants"; import { PublicApiResponse } from "./public-api.types"; import { Post } from "@zenblog/types"; import { throwError } from "./public-api.errors"; -async function verifyAPIKey(header: string, blogId: string) { - const supabase = createClient(); - const unhashedKey = header.split(" ")[1]; - - if (!unhashedKey) { - return false; - } - - const { data, error } = await supabase - .from("blogs") - .select("access_token") - .eq("id", blogId) - .single(); - - if (error) { - return false; - } - - if (!data?.access_token) { - return false; - } - - const isValid = await bcrypt.compare(unhashedKey, data?.access_token); - return isValid; -} - const app = new Hono() .basePath("/api/public") .use("*", logger()) @@ -45,22 +18,11 @@ app.get(posts.path, async (c) => { const offset = parseInt(c.req.query("offset") || "0"); const limit = parseInt(c.req.query("limit") || "30"); const supabase = createClient(); - const authHeader = c.req.header("Authorization"); if (!blogId) { return throwError(c, "MISSING_BLOG_ID"); } - if (!authHeader) { - return throwError(c, "MISSING_API_KEY"); - } - - const isValid = await verifyAPIKey(authHeader, blogId); - - if (!isValid) { - return throwError(c, "INVALID_API_KEY"); - } - const { data: posts, error } = await supabase .from("posts_v7") .select("title, slug, published_at, excerpt, cover_image, tags, category") @@ -89,22 +51,11 @@ app.get(postBySlug.path, async (c) => { const blogId = c.req.param("blogId"); const slug = c.req.param("slug"); const supabase = createClient(); - const authHeader = c.req.header("Authorization"); if (!blogId || !slug) { return throwError(c, "MISSING_BLOG_ID_OR_SLUG"); } - if (!authHeader) { - return throwError(c, "MISSING_API_KEY"); - } - - const isValid = await verifyAPIKey(authHeader, blogId); - - if (!isValid) { - return throwError(c, "INVALID_API_KEY"); - } - const { data: post, error } = await supabase .from("posts_v7") .select( @@ -124,22 +75,11 @@ app.get(postBySlug.path, async (c) => { app.get(categories.path, async (c) => { const blogId = c.req.param("blogId"); const supabase = createClient(); - const authHeader = c.req.header("Authorization"); if (!blogId) { return throwError(c, "MISSING_BLOG_ID"); } - if (!authHeader) { - return throwError(c, "MISSING_API_KEY"); - } - - const isValid = await verifyAPIKey(authHeader, blogId); - - if (!isValid) { - return throwError(c, "INVALID_API_KEY"); - } - const { data: categories, error } = await supabase .from("categories") .select("name, slug") @@ -155,22 +95,11 @@ app.get(categories.path, async (c) => { app.get(tags.path, async (c) => { const blogId = c.req.param("blogId"); const supabase = createClient(); - const authHeader = c.req.header("Authorization"); if (!blogId) { return throwError(c, "MISSING_BLOG_ID"); } - if (!authHeader) { - return throwError(c, "MISSING_API_KEY"); - } - - const isValid = await verifyAPIKey(authHeader, blogId); - - if (!isValid) { - return throwError(c, "INVALID_API_KEY"); - } - const { data: tags, error } = await supabase .from("blog_tags") .select("name, slug") diff --git a/packages/zenblog/dist/index.d.ts b/packages/zenblog/dist/index.d.ts index a9ab757..b1cb6fe 100644 --- a/packages/zenblog/dist/index.d.ts +++ b/packages/zenblog/dist/index.d.ts @@ -1,11 +1,10 @@ import { Category, Post, PostWithContent, Tag } from "@zenblog/types"; type CreateClientOpts = { - accessToken: string; blogId: string; _url?: string; _debug?: boolean; }; -export declare function createZenblogClient({ accessToken, blogId, _url, _debug, }: CreateClientOpts): { +export declare function createZenblogClient({ blogId, _url, _debug, }: CreateClientOpts): { posts: { list: ({ limit, offset, cache }?: { cache?: RequestInit["cache"]; diff --git a/packages/zenblog/dist/index.d.ts.map b/packages/zenblog/dist/index.d.ts.map index 4f35d5a..f9d3c16 100644 --- a/packages/zenblog/dist/index.d.ts.map +++ b/packages/zenblog/dist/index.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAsCtE,KAAK,gBAAgB,GAAG;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AACF,wBAAgB,mBAAmB,CAAC,EAClC,WAAW,EACX,MAAM,EACN,IAAI,EACJ,MAAM,GACP,EAAE,gBAAgB;;;oBAqBP,WAAW,CAAC,OAAO,CAAC;;;;kBAYP,IAAI,EAAE;;;kBAYL,MAAM;;oBAxBpB,WAAW,CAAC,OAAO,CAAC;;;0BA0BvB,QAAQ;YAAE,IAAI,EAAE,eAAe,CAAA;SAAE,CAAC;;;;kBAUI,QAAQ,EAAE;;;;;kBASV,GAAG,EAAE;;;EASnD"} \ No newline at end of file +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AA0CtE,KAAK,gBAAgB,GAAG;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AACF,wBAAgB,mBAAmB,CAAC,EAClC,MAAM,EACN,IAAI,EACJ,MAAM,GACP,EAAE,gBAAgB;;;oBAiBP,WAAW,CAAC,OAAO,CAAC;;;;kBAYP,IAAI,EAAE;;;kBAYL,MAAM;;oBAxBpB,WAAW,CAAC,OAAO,CAAC;;;0BA0BvB,QAAQ;YAAE,IAAI,EAAE,eAAe,CAAA;SAAE,CAAC;;;;kBAUI,QAAQ,EAAE;;;;;kBASV,GAAG,EAAE;;;EASnD"} \ No newline at end of file diff --git a/packages/zenblog/dist/index.js b/packages/zenblog/dist/index.js index cf6a7cf..95283b7 100644 --- a/packages/zenblog/dist/index.js +++ b/packages/zenblog/dist/index.js @@ -13,14 +13,19 @@ function createFetcher(config, log) { const reqOpts = { ...opts, headers: { - Authorization: config.accessToken, "Content-Type": "application/json", ...opts.headers, }, }; log("fetch ", URL, reqOpts.method); const res = await fetch(URL, reqOpts); - const json = await res.json(); + let json; + try { + json = await res.json(); + } + catch (e) { + (0, lib_1.throwError)("Failed to parse JSON response from API", e); + } if (!res.ok) { (0, lib_1.throwError)("Error fetching data from API", res); } @@ -32,17 +37,13 @@ function createFetcher(config, log) { } }; } -function createZenblogClient({ accessToken, blogId, _url, _debug, }) { +function createZenblogClient({ blogId, _url, _debug, }) { if (typeof window !== "undefined") { (0, lib_1.throwError)("Zenblog is not supported in the browser. Make sure you don't leak your access token."); } - if (!accessToken) { - (0, lib_1.throwError)("accessToken is required"); - } const logger = (0, lib_1.createLogger)(_debug || false); const fetcher = createFetcher({ - url: _url || "https://zenblog.com/api/v1/public", - accessToken, + url: _url || "https://zenblog.com/api/public", blogId, }, logger); return { diff --git a/packages/zenblog/dist/index.js.map b/packages/zenblog/dist/index.js.map index 477caf6..0c077cf 100644 --- a/packages/zenblog/dist/index.js.map +++ b/packages/zenblog/dist/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,+BAAiD;AAEjD,SAAS,aAAa,CAAC,GAAwB;IAC7C,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,GAAG,CAAC,CAAC;IACxC,OAAO,MAAM,CAAC,QAAQ,EAAE,CAAC;AAC3B,CAAC;AAED,SAAS,aAAa,CACpB,MAAuC,EACvC,GAA6B;IAE7B,OAAO,KAAK,UAAU,MAAM,CAAC,IAAY,EAAE,IAAiB;QAC1D,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,GAAG,UAAU,MAAM,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC;YAC3D,MAAM,OAAO,GAAG;gBACd,GAAG,IAAI;gBACP,OAAO,EAAE;oBACP,cAAc,EAAE,kBAAkB;oBAClC,GAAG,IAAI,CAAC,OAAO;iBAChB;aACF,CAAC;YAEF,GAAG,CAAC,QAAQ,EAAE,GAAG,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;YACnC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;YACtC,IAAI,IAAI,CAAC;YACT,IAAI,CAAC;gBACH,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;YAC1B,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,IAAA,gBAAU,EAAC,wCAAwC,EAAE,CAAC,CAAC,CAAC;YAC1D,CAAC;YAED,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,IAAA,gBAAU,EAAC,8BAA8B,EAAE,GAAG,CAAC,CAAC;YAClD,CAAC;YAED,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,kBAAkB,EAAE,KAAK,CAAC,CAAC;YACzC,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AAOD,SAAgB,mBAAmB,CAAC,EAClC,MAAM,EACN,IAAI,EACJ,MAAM,GACW;IACjB,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;QAClC,IAAA,gBAAU,EACR,sFAAsF,CACvF,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,IAAA,kBAAY,EAAC,MAAM,IAAI,KAAK,CAAC,CAAC;IAC7C,MAAM,OAAO,GAAG,aAAa,CAC3B;QACE,GAAG,EAAE,IAAI,IAAI,gCAAgC;QAC7C,MAAM;KACP,EACD,MAAM,CACP,CAAC;IAOF,OAAO;QACL,KAAK,EAAE;YACL,IAAI,EAAE,KAAK,WACT,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,KAAc;gBAClC,KAAK,EAAE,EAAE;gBACT,MAAM,EAAE,CAAC;gBACT,KAAK,EAAE,SAAS;aACjB;gBAED,MAAM,IAAI,GAAG,MAAM,OAAO,CACxB,SAAS,aAAa,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,EAAE,EAC3C;oBACE,MAAM,EAAE,KAAK;oBACb,KAAK;iBACN,CACF,CAAC;gBAEF,OAAO,IAAwB,CAAC;YAClC,CAAC;YACD,GAAG,EAAE,KAAK,WACR,EAAE,IAAI,EAAoB,EAC1B,IAAc;gBAEd,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,SAAS,IAAI,EAAE,EAAE;oBAC1C,MAAM,EAAE,KAAK;oBACb,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,SAAS;iBAChC,CAAC,CAAC;gBAEH,OAAO,IAAiC,CAAC;YAC3C,CAAC;SACF;QACD,UAAU,EAAE;YACV,IAAI,EAAE,KAAK;gBACT,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,YAAY,EAAE;oBACvC,MAAM,EAAE,KAAK;iBACd,CAAC,CAAC;gBAEH,OAAO,IAA4B,CAAC;YACtC,CAAC;SACF;QACD,IAAI,EAAE;YACJ,IAAI,EAAE,KAAK;gBACT,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,MAAM,EAAE;oBACjC,MAAM,EAAE,KAAK;iBACd,CAAC,CAAC;gBAEH,OAAO,IAAuB,CAAC;YACjC,CAAC;SACF;KACF,CAAC;AACJ,CAAC;AA3ED,kDA2EC"} \ No newline at end of file diff --git a/packages/zenblog/package.json b/packages/zenblog/package.json index bdd3dbe..d841286 100644 --- a/packages/zenblog/package.json +++ b/packages/zenblog/package.json @@ -1,6 +1,6 @@ { "name": "zenblog", - "version": "0.4.0", + "version": "0.5.0", "description": "The typescript client for zenblog", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/zenblog/src/index.ts b/packages/zenblog/src/index.ts index 328bc16..7435871 100644 --- a/packages/zenblog/src/index.ts +++ b/packages/zenblog/src/index.ts @@ -6,7 +6,7 @@ function toQueryString(obj: Record) { } function createFetcher( - config: { url: string; accessToken: string; blogId: string }, + config: { url: string; blogId: string }, log: (...args: any[]) => void ) { return async function _fetch(path: string, opts: RequestInit) { @@ -15,7 +15,6 @@ function createFetcher( const reqOpts = { ...opts, headers: { - Authorization: config.accessToken, "Content-Type": "application/json", ...opts.headers, }, @@ -23,7 +22,12 @@ function createFetcher( log("fetch ", URL, reqOpts.method); const res = await fetch(URL, reqOpts); - const json = await res.json(); + let json; + try { + json = await res.json(); + } catch (e) { + throwError("Failed to parse JSON response from API", e); + } if (!res.ok) { throwError("Error fetching data from API", res); @@ -38,13 +42,11 @@ function createFetcher( } type CreateClientOpts = { - accessToken: string; blogId: string; _url?: string; _debug?: boolean; }; export function createZenblogClient({ - accessToken, blogId, _url, _debug, @@ -54,15 +56,11 @@ export function createZenblogClient({ "Zenblog is not supported in the browser. Make sure you don't leak your access token." ); } - if (!accessToken) { - throwError("accessToken is required"); - } const logger = createLogger(_debug || false); const fetcher = createFetcher( { - url: _url || "https://zenblog.com/api/v1/public", - accessToken, + url: _url || "https://zenblog.com/api/public", blogId, }, logger