From 32701491277db806b6174787fa1f9bca2e109f16 Mon Sep 17 00:00:00 2001 From: Sid Date: Fri, 6 Oct 2023 13:02:34 +0800 Subject: [PATCH 1/9] feat: use Typesense get articles --- packages/karbon/package.json | 3 +- packages/karbon/src/runtime/api/article.ts | 91 ++++--------------- packages/karbon/src/runtime/api/feed.ts | 41 +-------- .../runtime/composables/typesense-client.ts | 49 ++++++++++ yarn.lock | 3 +- 5 files changed, 75 insertions(+), 112 deletions(-) create mode 100644 packages/karbon/src/runtime/composables/typesense-client.ts diff --git a/packages/karbon/package.json b/packages/karbon/package.json index 1221e243..63965ca2 100644 --- a/packages/karbon/package.json +++ b/packages/karbon/package.json @@ -174,6 +174,7 @@ "tiny-invariant": "^1.3.1", "ts-pattern": "^5.0.5", "type-fest": "^4.3.1", + "typesense": "^1.7.1", "typesense-instantsearch-adapter": "^2.7.1", "unbuild": "^2.0.0", "unenv": "^1.7.4", @@ -229,4 +230,4 @@ "access": "public" }, "gitHead": "8df1f4d5837a7e2ddbff6cc79f5fec256c34a394" -} \ No newline at end of file +} diff --git a/packages/karbon/src/runtime/api/article.ts b/packages/karbon/src/runtime/api/article.ts index c2baeebb..0f149b09 100644 --- a/packages/karbon/src/runtime/api/article.ts +++ b/packages/karbon/src/runtime/api/article.ts @@ -5,80 +5,18 @@ import { encrypt } from 'micro-aes-gcm' // This file contains global crypto polyfill import { CompactEncrypt } from '@storipress/jose-browser' import { useStoripressClient } from '../composables/storipress-client' +import type { TypesenseFilter } from '../composables/typesense-client' +import { PER_PAGE, getSearchQuery, useTypesenseClient } from '../composables/typesense-client' import { splitPaidContent } from '../lib/split-paid-content' import type { NormalSegment } from '../lib/split-article' import { splitArticle } from '../lib/split-article' import { getStoripressConfig } from '../composables/storipress-base-client' import { verboseInvariant } from '../utils/verbose-invariant' -import { getAllWithPagination } from './helper' import type { PaidContent, RawArticleLike, _NormalizeArticle } from './normalize-article' import { normalizeArticle } from './normalize-article' export type { NormalizeArticle, PaidContent } from './normalize-article' -export const ListArticles = gql` - query ListArticles($page: Int!) { - articles(page: $page, sortBy: [{ column: PUBLISHED_AT, order: DESC }], published: true) { - paginatorInfo { - lastPage - hasMorePages - count - } - data { - id - title - blurb - slug - sid - published_at - updated_at - featured - plan - cover - seo - layout { - id - name - } - desk { - id - name - slug - layout { - id - name - } - desk { - id - name - slug - layout { - id - name - } - } - } - tags { - id - slug - name - } - authors { - id - slug - bio - socials - avatar - email - location - first_name - last_name - full_name - } - } - } - } -` const GetArticle = gql` query GetArticle($id: ID!) { article(id: $id) { @@ -315,14 +253,23 @@ const GetArticle = gql` } ` -export async function listArticles(filter?: { desk: string; tag: string; author: string }) { - return getAllWithPagination(ListArticles, filter, ({ articles: { paginatorInfo, data } }) => { - const res = data.map((data: RawArticleLike) => normalizeArticle(data)) - return { - paginatorInfo, - data: res, - } - }) +export async function listArticles(filter?: TypesenseFilter) { + const typesenseClient = useTypesenseClient() + const documents = typesenseClient?.collections('articles').documents() + + const articles = [] + let hasMore = true + let page = 1 + while (hasMore) { + const searchResult = await documents?.search(getSearchQuery(page, filter), {}) + const currentPageArticles = + searchResult?.hits?.map(({ document }) => normalizeArticle(document as RawArticleLike)) ?? [] + articles.push(...currentPageArticles) + + hasMore = searchResult.found > searchResult.page * PER_PAGE + page = searchResult.page + 1 + } + return articles } export async function getArticle(id: string) { diff --git a/packages/karbon/src/runtime/api/feed.ts b/packages/karbon/src/runtime/api/feed.ts index 52ff873e..e04a3a36 100644 --- a/packages/karbon/src/runtime/api/feed.ts +++ b/packages/karbon/src/runtime/api/feed.ts @@ -1,35 +1,6 @@ import { gql } from '@apollo/client/core/index.js' import { useStoripressClient } from '../composables/storipress-client' -import { getAllWithPagination } from './helper' -import type { RawArticleLike } from './normalize-article' -import { normalizeArticle } from './normalize-article' - -const ListArticles = gql` - query ListArticles($page: Int!, $desk: ID, $desk_ids: [ID!]) { - articles( - page: $page - desk: $desk - desk_ids: $desk_ids - sortBy: [{ column: UPDATED_AT, order: DESC }] - published: true - ) { - paginatorInfo { - count - lastPage - hasMorePages - } - data { - id - title - slug - sid - published_at - html - plaintext - } - } - } -` +import { listArticles } from './article' const GetDesk = gql` query GetDesk($slug: String) { @@ -51,14 +22,8 @@ const GetDesk = gql` } ` -export function listFeedArticles(filter?: { desk: string; tag: string; author: string; desk_ids: string }) { - return getAllWithPagination(ListArticles, filter, ({ articles: { paginatorInfo, data } }) => { - const res = data.map((data: RawArticleLike) => normalizeArticle(data)) - return { - paginatorInfo, - data: res, - } - }) +export function listFeedArticles(filter?: { desk: string; tag: string; author: string; desk_ids: string[] }) { + return listArticles(filter) } export async function getDeskWithSlug(slug: string) { diff --git a/packages/karbon/src/runtime/composables/typesense-client.ts b/packages/karbon/src/runtime/composables/typesense-client.ts new file mode 100644 index 00000000..cca5583c --- /dev/null +++ b/packages/karbon/src/runtime/composables/typesense-client.ts @@ -0,0 +1,49 @@ +import { SearchClient } from 'typesense' +import { getStoripressConfig } from './storipress-base-client' + +let typesenseClient: SearchClient + +export function useTypesenseClient() { + if (typesenseClient) return typesenseClient + + const storipress = getStoripressConfig() + typesenseClient = new SearchClient({ + nodes: [ + { + host: storipress.searchDomain ?? '', + port: 443, + protocol: 'https', + }, + ], + apiKey: storipress.searchKey, + connectionTimeoutSeconds: 5, + }) + return typesenseClient +} + +export interface TypesenseFilter { + desk?: string + tag?: string + author?: string + desk_ids?: string[] +} + +export const PER_PAGE = 100 + +export function getSearchQuery(page = 1, filter: TypesenseFilter = {}) { + const { desk, tag, author, desk_ids: deskIds } = filter + let filterBy = '' + if (desk) filterBy += ` && (desk.id:= ${desk} || desk.desk.id:= ${desk})` + if (tag) filterBy += ` && tag_ids:=${tag}` + if (author) filterBy += ` && author_ids:${author}` + if (deskIds) filterBy += ` && desk_id:[${deskIds.join()}` + + return { + q: '*', + sort_by: 'published_at:desc,order:asc', + filter_by: `published:=true${filterBy}`, + per_page: PER_PAGE, + page, + preset: `list-articles-${page}`, + } +} diff --git a/yarn.lock b/yarn.lock index 30b4c97f..0cb94c80 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3448,6 +3448,7 @@ __metadata: tsx: 3.12.10 type-fest: ^4.3.1 typescript: 5.2.2 + typesense: ^1.7.1 typesense-instantsearch-adapter: ^2.7.1 unbuild: ^2.0.0 unenv: ^1.7.4 @@ -17042,7 +17043,7 @@ __metadata: languageName: node linkType: hard -"typesense@npm:^1.7.0": +"typesense@npm:^1.7.0, typesense@npm:^1.7.1": version: 1.7.1 resolution: "typesense@npm:1.7.1" dependencies: From 7dfe7ffe94065d7f7f3aa069ededc03d89eeda98 Mon Sep 17 00:00:00 2001 From: Sid Date: Sat, 7 Oct 2023 06:06:54 +0800 Subject: [PATCH 2/9] feat: use Typesense get articles for sitemap --- packages/karbon/src/runtime/api/sitemap.ts | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/karbon/src/runtime/api/sitemap.ts b/packages/karbon/src/runtime/api/sitemap.ts index fc8b78dc..2ffdd6ed 100644 --- a/packages/karbon/src/runtime/api/sitemap.ts +++ b/packages/karbon/src/runtime/api/sitemap.ts @@ -3,7 +3,7 @@ import { identity } from 'remeda' import { createStoripressClient } from '../composables/storipress-client' import { storipressConfigCtx } from '../composables/storipress-base-client' import type { ModuleRuntimeConfig } from '../types' -import { getAllWithPaginationViaGetPage } from './helper' +import { PER_PAGE, getSearchQuery, useTypesenseClient } from '../composables/typesense-client' const ListArticles = gql` query ListArticles($page: Int!) { @@ -130,17 +130,25 @@ export const payloadScopes: ResourceScope[] = [ export async function getResources(runtimeConfig?: ModuleRuntimeConfig['storipress']) { runtimeConfig && storipressConfigCtx.set(runtimeConfig) const client = createStoripressClient() + const typesenseClient = useTypesenseClient() const result = await Promise.all( payloadScopes.map(async ({ payloadScope, query, queryKey, filter = identity }) => { let resources: any = [] switch (payloadScope) { case 'posts': { - const getPage = async (page: number) => { - const { data } = await client.query({ query, variables: { page } }) - return data.articles + const documents = typesenseClient?.collections('articles').documents() + + let hasMore = true + let page = 1 + while (hasMore) { + const searchResult = await documents?.search(getSearchQuery(page), {}) + const currentPageArticles = searchResult?.hits?.map(({ document }) => document) ?? [] + resources.push(...currentPageArticles) + + hasMore = searchResult.found > searchResult.page * PER_PAGE + page = searchResult.page + 1 } - resources = await getAllWithPaginationViaGetPage(getPage) break } default: { From 20deb041c5b25df69f7be566375298e692924edc Mon Sep 17 00:00:00 2001 From: Sid Date: Sat, 7 Oct 2023 07:15:49 +0800 Subject: [PATCH 3/9] feat: add typesense filter_by --- .../runtime/composables/typesense-client.ts | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/packages/karbon/src/runtime/composables/typesense-client.ts b/packages/karbon/src/runtime/composables/typesense-client.ts index cca5583c..8bf21160 100644 --- a/packages/karbon/src/runtime/composables/typesense-client.ts +++ b/packages/karbon/src/runtime/composables/typesense-client.ts @@ -22,26 +22,28 @@ export function useTypesenseClient() { } export interface TypesenseFilter { - desk?: string - tag?: string - author?: string desk_ids?: string[] + author_ids?: string[] + author_names?: string[] + tag_ids?: string[] + tag_names?: string[] } export const PER_PAGE = 100 export function getSearchQuery(page = 1, filter: TypesenseFilter = {}) { - const { desk, tag, author, desk_ids: deskIds } = filter - let filterBy = '' - if (desk) filterBy += ` && (desk.id:= ${desk} || desk.desk.id:= ${desk})` - if (tag) filterBy += ` && tag_ids:=${tag}` - if (author) filterBy += ` && author_ids:${author}` - if (deskIds) filterBy += ` && desk_id:[${deskIds.join()}` + const { desk_ids, author_ids, author_names, tag_ids, tag_names } = filter + let filterBy = 'published:=true' + if (desk_ids?.length) filterBy += ` && desk_id:=[${desk_ids.join()}]` + if (author_ids?.length) filterBy += ` && author_ids:=[${author_ids.join()}]` + if (author_names?.length) filterBy += ` && author_names:=[${author_names.join()}]` + if (tag_ids?.length) filterBy += ` && tag_ids:=[${tag_ids.join()}]` + if (tag_names?.length) filterBy += ` && tag_names:=[${tag_names.join()}]` return { q: '*', sort_by: 'published_at:desc,order:asc', - filter_by: `published:=true${filterBy}`, + filter_by: filterBy, per_page: PER_PAGE, page, preset: `list-articles-${page}`, From 53bb49b69a4953e30985dc9a9298350a1895e08a Mon Sep 17 00:00:00 2001 From: Sid Date: Wed, 11 Oct 2023 14:27:03 +0800 Subject: [PATCH 4/9] feat: modify listFeedArticles filter fromat --- packages/karbon/src/runtime/api/feed.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/karbon/src/runtime/api/feed.ts b/packages/karbon/src/runtime/api/feed.ts index e04a3a36..9880b91e 100644 --- a/packages/karbon/src/runtime/api/feed.ts +++ b/packages/karbon/src/runtime/api/feed.ts @@ -1,5 +1,6 @@ import { gql } from '@apollo/client/core/index.js' import { useStoripressClient } from '../composables/storipress-client' +import type { TypesenseFilter } from '../composables/typesense-client' import { listArticles } from './article' const GetDesk = gql` @@ -22,7 +23,7 @@ const GetDesk = gql` } ` -export function listFeedArticles(filter?: { desk: string; tag: string; author: string; desk_ids: string[] }) { +export function listFeedArticles(filter: TypesenseFilter = {}) { return listArticles(filter) } From dce8ceff00190ca78bee9f949efaa91ce4d7600a Mon Sep 17 00:00:00 2001 From: Sid Date: Wed, 11 Oct 2023 14:31:52 +0800 Subject: [PATCH 5/9] fix: wrong Typesense search query schema --- packages/karbon/src/runtime/composables/typesense-client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/karbon/src/runtime/composables/typesense-client.ts b/packages/karbon/src/runtime/composables/typesense-client.ts index 8bf21160..76f588fa 100644 --- a/packages/karbon/src/runtime/composables/typesense-client.ts +++ b/packages/karbon/src/runtime/composables/typesense-client.ts @@ -46,6 +46,6 @@ export function getSearchQuery(page = 1, filter: TypesenseFilter = {}) { filter_by: filterBy, per_page: PER_PAGE, page, - preset: `list-articles-${page}`, + query_by: 'title', } } From 2d849e57cf6043abf1df77f2c5b07525aa94148d Mon Sep 17 00:00:00 2001 From: Sid Date: Thu, 12 Oct 2023 09:27:38 +0800 Subject: [PATCH 6/9] fix: sitemap / feed --- packages/karbon/src/runtime/api/feed.ts | 7 ++- .../src/runtime/api/normalize-article.ts | 1 + packages/karbon/src/runtime/api/sitemap.ts | 15 +----- .../src/runtime/routes/atom-desk.xml.ts | 53 ++++++++----------- 4 files changed, 27 insertions(+), 49 deletions(-) diff --git a/packages/karbon/src/runtime/api/feed.ts b/packages/karbon/src/runtime/api/feed.ts index 9880b91e..4ef62878 100644 --- a/packages/karbon/src/runtime/api/feed.ts +++ b/packages/karbon/src/runtime/api/feed.ts @@ -1,7 +1,5 @@ import { gql } from '@apollo/client/core/index.js' import { useStoripressClient } from '../composables/storipress-client' -import type { TypesenseFilter } from '../composables/typesense-client' -import { listArticles } from './article' const GetDesk = gql` query GetDesk($slug: String) { @@ -23,8 +21,9 @@ const GetDesk = gql` } ` -export function listFeedArticles(filter: TypesenseFilter = {}) { - return listArticles(filter) +export async function listFeedArticles() { + const allArticles = (await $fetch('/_storipress/posts/__all.json')) ?? [] + return allArticles } export async function getDeskWithSlug(slug: string) { diff --git a/packages/karbon/src/runtime/api/normalize-article.ts b/packages/karbon/src/runtime/api/normalize-article.ts index 22505c2d..f2772463 100644 --- a/packages/karbon/src/runtime/api/normalize-article.ts +++ b/packages/karbon/src/runtime/api/normalize-article.ts @@ -24,6 +24,7 @@ export interface RawArticleLike { plaintext: string plan: ArticlePlan authors: RawUserLike[] + published_at: string } export interface PaidContent { diff --git a/packages/karbon/src/runtime/api/sitemap.ts b/packages/karbon/src/runtime/api/sitemap.ts index 2ffdd6ed..aa26eee4 100644 --- a/packages/karbon/src/runtime/api/sitemap.ts +++ b/packages/karbon/src/runtime/api/sitemap.ts @@ -3,7 +3,6 @@ import { identity } from 'remeda' import { createStoripressClient } from '../composables/storipress-client' import { storipressConfigCtx } from '../composables/storipress-base-client' import type { ModuleRuntimeConfig } from '../types' -import { PER_PAGE, getSearchQuery, useTypesenseClient } from '../composables/typesense-client' const ListArticles = gql` query ListArticles($page: Int!) { @@ -130,25 +129,13 @@ export const payloadScopes: ResourceScope[] = [ export async function getResources(runtimeConfig?: ModuleRuntimeConfig['storipress']) { runtimeConfig && storipressConfigCtx.set(runtimeConfig) const client = createStoripressClient() - const typesenseClient = useTypesenseClient() const result = await Promise.all( payloadScopes.map(async ({ payloadScope, query, queryKey, filter = identity }) => { let resources: any = [] switch (payloadScope) { case 'posts': { - const documents = typesenseClient?.collections('articles').documents() - - let hasMore = true - let page = 1 - while (hasMore) { - const searchResult = await documents?.search(getSearchQuery(page), {}) - const currentPageArticles = searchResult?.hits?.map(({ document }) => document) ?? [] - resources.push(...currentPageArticles) - - hasMore = searchResult.found > searchResult.page * PER_PAGE - page = searchResult.page + 1 - } + resources = (await $fetch('/_storipress/posts/__all.json')) ?? [] break } default: { diff --git a/packages/karbon/src/runtime/routes/atom-desk.xml.ts b/packages/karbon/src/runtime/routes/atom-desk.xml.ts index 099a893f..b89de539 100644 --- a/packages/karbon/src/runtime/routes/atom-desk.xml.ts +++ b/packages/karbon/src/runtime/routes/atom-desk.xml.ts @@ -2,8 +2,9 @@ import { defineEventHandler, sendNoContent, setHeader } from 'h3' import { Feed } from 'feed' import { encodePath, joinURL, withTrailingSlash } from 'ufo' import path from 'pathe' -import { getDeskWithSlug, listFeedArticles } from '@storipress/karbon/internal' +import { getDeskWithSlug } from '@storipress/karbon/internal' import type { Author } from '../composables/page-meta' +import { listArticles } from '../api/article' import { useRuntimeConfig } from '#imports' import urls from '#sp-internal/storipress-urls.mjs' @@ -37,23 +38,15 @@ export default defineEventHandler(async (e) => { const deskIds: string[] = desk.desks?.map(({ id }: { id: string }) => id) ?? [] - type Filter = Record<'desk' | 'desk_ids', string | string[]> - const filter = {} as Filter - if (deskIds.length !== 0) { - filter.desk_ids = deskIds - } else { - filter.desk = desk.id - } - const runtimeConfig = useRuntimeConfig() - const articles = await listFeedArticles(filter) + const articles = await listArticles({ desk_ids: deskIds }) - const siteUrl = runtimeConfig.public.siteUrl + const siteUrl = runtimeConfig.public.siteUrl as string const feed = new Feed({ - id: withTrailingSlash(runtimeConfig.public.siteUrl), - link: withTrailingSlash(runtimeConfig.public.siteUrl), - title: runtimeConfig.public.siteName, - description: runtimeConfig.public.siteDescription, + id: withTrailingSlash(runtimeConfig.public.siteUrl as string), + link: withTrailingSlash(runtimeConfig.public.siteUrl as string), + title: runtimeConfig.public.siteName as string, + description: runtimeConfig.public.siteDescription as string, updated: new Date(), feedLinks: { atom: joinURL(siteUrl, `/atom/${fileName}`), @@ -61,23 +54,21 @@ export default defineEventHandler(async (e) => { copyright: `© ${runtimeConfig.public.siteName} ${new Date().getFullYear()} All Rights Reserved`, }) - articles - .filter((article: TArticle) => article.published_at) - .forEach((article: TArticle) => { - const id = encodePath(urls.article.toURL(article, urls.article._context)) - feed.addItem({ - title: article.title, - id: joinURL(siteUrl, id), - link: joinURL(siteUrl, id), - description: article.plaintext.slice(0, 120), - date: new Date(article.published_at), - author: - article.author?.map((author) => ({ - name: author.name, - })) || [], - content: article.html, - }) + articles.forEach((article) => { + const id = encodePath(urls.article.toURL(article, urls.article._context)) + feed.addItem({ + title: article.title, + id: joinURL(siteUrl, id), + link: joinURL(siteUrl, id), + description: article.plaintext.slice(0, 120), + date: new Date(article.published_at), + author: + article.authors?.map((author) => ({ + name: author.name, + })) || [], + content: article.html, }) + }) return feed.atom1() }) From 9639cefc2943742ad3efa3ec3953bf350ab1f1bb Mon Sep 17 00:00:00 2001 From: Sid Date: Thu, 12 Oct 2023 09:35:27 +0800 Subject: [PATCH 7/9] refactor: fix deepSource issue --- .../karbon/src/runtime/routes/atom-desk.xml.ts | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/packages/karbon/src/runtime/routes/atom-desk.xml.ts b/packages/karbon/src/runtime/routes/atom-desk.xml.ts index b89de539..62c142b3 100644 --- a/packages/karbon/src/runtime/routes/atom-desk.xml.ts +++ b/packages/karbon/src/runtime/routes/atom-desk.xml.ts @@ -3,34 +3,20 @@ import { Feed } from 'feed' import { encodePath, joinURL, withTrailingSlash } from 'ufo' import path from 'pathe' import { getDeskWithSlug } from '@storipress/karbon/internal' -import type { Author } from '../composables/page-meta' import { listArticles } from '../api/article' import { useRuntimeConfig } from '#imports' import urls from '#sp-internal/storipress-urls.mjs' -interface TArticle { - title: string - id: string - link: string - description: string - content: string - date: Date - author: Author[] - plaintext: string - html: string - published_at: string -} - export default defineEventHandler(async (e) => { setHeader(e, 'Content-Type', 'text/xml; charset=UTF-8') if (!process.dev) setHeader(e, 'Cache-Control', 'max-age=600, must-revalidate') - const fileName = e.context.params?.slug || '' + const fileName = e.context.params?.slug ?? '' if (!fileName.endsWith('.xml')) { return sendNoContent(e, 404) } - const slug = path.parse(fileName || '').name + const slug = path.parse(fileName).name const desk = await getDeskWithSlug(slug) if (!desk?.id) { return sendNoContent(e, 404) From a5e1860d26bb86d0221fe3d23236bb0813e03518 Mon Sep 17 00:00:00 2001 From: Sid Date: Mon, 16 Oct 2023 10:37:38 +0800 Subject: [PATCH 8/9] fix: import listArticles from internal --- packages/karbon/src/runtime/routes/atom-desk.xml.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/karbon/src/runtime/routes/atom-desk.xml.ts b/packages/karbon/src/runtime/routes/atom-desk.xml.ts index 62c142b3..3ac38deb 100644 --- a/packages/karbon/src/runtime/routes/atom-desk.xml.ts +++ b/packages/karbon/src/runtime/routes/atom-desk.xml.ts @@ -2,8 +2,7 @@ import { defineEventHandler, sendNoContent, setHeader } from 'h3' import { Feed } from 'feed' import { encodePath, joinURL, withTrailingSlash } from 'ufo' import path from 'pathe' -import { getDeskWithSlug } from '@storipress/karbon/internal' -import { listArticles } from '../api/article' +import { getDeskWithSlug, listArticles } from '@storipress/karbon/internal' import { useRuntimeConfig } from '#imports' import urls from '#sp-internal/storipress-urls.mjs' From 4ace651ba26cca121895154a5acaa2448dcea76c Mon Sep 17 00:00:00 2001 From: Sid Date: Tue, 17 Oct 2023 11:33:02 +0800 Subject: [PATCH 9/9] fix: article-filter by normalize article --- .../src/runtime/api/normalize-article.ts | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/packages/karbon/src/runtime/api/normalize-article.ts b/packages/karbon/src/runtime/api/normalize-article.ts index f2772463..c4239259 100644 --- a/packages/karbon/src/runtime/api/normalize-article.ts +++ b/packages/karbon/src/runtime/api/normalize-article.ts @@ -1,7 +1,7 @@ import { destr } from 'destr' import truncate from 'lodash.truncate' import type { Segment } from '../lib/split-article' -import type { ArticlePlan } from '../types' +import type { ArticleDesk, ArticlePlan, ArticleTag } from '../types' import { useArticleFilter } from '#imports' export interface RawUserLike { @@ -24,6 +24,8 @@ export interface RawArticleLike { plaintext: string plan: ArticlePlan authors: RawUserLike[] + tags: ArticleTag[] + desk: ArticleDesk published_at: string } @@ -54,9 +56,12 @@ export function normalizeArticle({ html, id, authors, + desk, + tags, ...rest }: RawArticleLike) { const articleFilter = useArticleFilter() + const rootDesk = desk.desk ? { desk: { ...desk.desk, id: String(desk.desk.id) } } : {} return { ...rest, @@ -75,11 +80,21 @@ export function normalizeArticle({ separator: /,? +/, }), cover: destr(cover), - authors: authors?.map(({ socials, ...rest }) => ({ + authors: authors?.map(({ socials, id, ...rest }) => ({ ...rest, + id: String(id), socials: destr(socials), name: rest.full_name, })), + desk: { + ...desk, + ...rootDesk, + id: String(desk.id), + }, + tags: tags?.map(({ id, ...rest }) => ({ + ...rest, + id: String(id), + })), } }