From f24a8834ea9ae0bbd8f2072928894d51d899a0ca Mon Sep 17 00:00:00 2001 From: Ou Date: Mon, 21 Oct 2024 01:38:58 +0800 Subject: [PATCH] feat: add some sources --- package.json | 1 + pnpm-lock.yaml | 3 ++ public/icons/cls.png | Bin 0 -> 1795 bytes server/api/s/[id].ts | 2 +- server/sources/36kr.ts | 5 +- server/sources/cankaoxiaoxi.ts | 3 +- server/sources/cls/index.ts | 68 ++++++++++++++++++++++++++ server/sources/cls/utils.ts | 13 +++++ server/sources/coolapk/index.ts | 4 +- server/sources/coolapk/utils.ts | 11 ++--- server/sources/douyin.ts | 9 +--- server/sources/index.ts | 10 ++-- server/sources/ithome.ts | 1 - server/sources/sputniknewscn.ts | 5 +- server/sources/toutiao.ts | 7 +-- server/sources/v2ex.ts | 1 - server/sources/wallstreetcn.ts | 84 ++++++++++++++++++++++++++------ server/sources/weibo.ts | 2 - server/sources/zaobao.ts | 1 - server/sources/zhihu.ts | 1 - server/utils/crypto.ts | 24 +++++++++ server/utils/source.ts | 4 +- shared/metadata.ts | 2 +- shared/sources.ts | 36 ++++++++++++-- shared/types.ts | 9 ++++ vite.config.ts | 1 + 26 files changed, 247 insertions(+), 60 deletions(-) create mode 100644 public/icons/cls.png create mode 100644 server/sources/cls/index.ts create mode 100644 server/sources/cls/utils.ts create mode 100644 server/utils/crypto.ts diff --git a/package.json b/package.json index c7e3c52..6ad0721 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "react-dom": "^18.3.1", "react-use": "^17.5.1", "sonner": "^1.5.0", + "uncrypto": "^0.1.3", "zod": "^3.23.8" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 32c0717..36ab8db 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -113,6 +113,9 @@ importers: sonner: specifier: ^1.5.0 version: 1.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + uncrypto: + specifier: ^0.1.3 + version: 0.1.3 zod: specifier: ^3.23.8 version: 3.23.8 diff --git a/public/icons/cls.png b/public/icons/cls.png new file mode 100644 index 0000000000000000000000000000000000000000..5e00ebb381ba42d518094a32c20714c2c240843d GIT binary patch literal 1795 zcmaJ?c~BEq91cODAXK!-jjlm1HQ8Jc63J!4IR+zS%2kz+EV3oZ#$=IzsDPlzsEmMs z*AxX5O9!+nptPtJK@kx_gM&~!P^ykf0kvR}ZV<44lF+Bg93%2*a{fluS~G7HYH^QTkKK42s8|dLzAQ$2*;Nru@DfXlx~7TA*noh^G(PX zhcotoB@t+ZXbnq-C`nQShNM%fF*Xk8%hjo+vIGbPVxdj2icNT1f0+QlayB8{OGFl_ z1yDR3n4*EgQbHuMlmr=5PT+C?UmXh*P(r8_&?yxvElbBHOzN_*y}=9;fJq3Nz$SbS zDncX%1c(L#yhz?e8HMHpFqkBY7t@DIUkOmj6mO8s1SxbPnZhD7S!4<@^$;*`8hIQm zROmnD3p=q1@hGZhfnZWn5-EvBLNuE|3X{nM$yAU^C1MDoHd%#AbwricWm-W9X=NH% zjlzfuFepl6kwlbDz#{#ef>J#rtI|%D2`d<=ld3@qiEKz|8YmL|KUArlL2J=a=u5o+ zDXf(wt06EH(jti(8P>Qs7lSJ`OQ3eCtootE!;x zTo}G9*i~WX$CdzDk=D;l*6~jqycZV1XIq;u9OrSe=P#Yd9ufGtt^@DqnT?Ad3#>bG zGqU_*$}SvuO?vp|($=*DFBf&JDy^?nnl?OpbBs3d@pfL z>`xaLkJ@wXoGomhQm?J*@%Xgx%&yJHC`%^v4dmr^Yxi*vk7|geUPk?7W|XLnZ`5fY zZtod*w7mFer=`)>g>+4%+xumI=DNHj(axnMKD!c1Dw>=8-OuN6j=S4ku6$Tr@@moG z-(L?7E#;-q7dU4)G2f0ZMb}x1SNR@? z?|F>2$d^JV&fK%F((X^JcDa!p6`Y^R6ILlYZJ5c!$?dME$^zz~C*#ymcE^D*x8N4u zKKFj#$62R4EaFAsKub+DoHLwW&Cai}ub_$R8d+miA&)u-f_nGmc~m?gKbJ@M{kqM# zd`Ay{bxs=mLT^#mD;{em0#4g_8N8LB)|rbH#v3@avfS2;;zLFToVD?Z-#296#TOED zhaA7ziCe!wj3B#-NIxUEe_*E#37?o$>Eh-tXkGFyasF;TJE#2B)2l6359*8L-s;y5 zr^o)vEID%vdQn>6+roL|d{{nsvfOe@L1amdzT16|Z9%8!yZQRA{G5Oh$K}>>)m2TB zQ(@gUaKg1Kw~w?lFGQ(Gd6hrLtXQ6>&#OISb*~R}AHB&5RtF1ek+2>c^8>Z#3!0v^ z*O{>WorC#vHbSl@QBkqr+Zd~c9P`Y@> => { const cacheTable = useCache() const now = Date.now() - if (cacheTable) { + if (process.env.NODE_ENV === "production" && cacheTable) { if (process.env.INIT_TABLE !== "false") await cacheTable.init() const cache = await cacheTable.get(id) if (cache) { diff --git a/server/sources/36kr.ts b/server/sources/36kr.ts index 9c071b4..3591f60 100644 --- a/server/sources/36kr.ts +++ b/server/sources/36kr.ts @@ -2,7 +2,8 @@ import type { NewsItem } from "@shared/types" import { load } from "cheerio" const quick = defineSource(async () => { - const url = "https://www.36kr.com/newsflashes" + const baseURL = "https://www.36kr.com" + const url = `${baseURL}/newsflashes` const response = await $fetch(url) as any const $ = load(response) const news: NewsItem[] = [] @@ -15,7 +16,7 @@ const quick = defineSource(async () => { const relativeDate = $el.find(".time") if (url && title && relativeDate) { news.push({ - url: `https://www.36kr.com${url}`, + url: `${baseURL}${url}`, title, id: url, extra: { diff --git a/server/sources/cankaoxiaoxi.ts b/server/sources/cankaoxiaoxi.ts index 5827397..fd40a2c 100644 --- a/server/sources/cankaoxiaoxi.ts +++ b/server/sources/cankaoxiaoxi.ts @@ -12,7 +12,6 @@ interface Res { export default defineSource(async () => { const res = await Promise.all(["zhongguo", "guandian", "gj"].map(k => $fetch(`https://china.cankaoxiaoxi.com/json/channel/${k}/list.json`) as Promise)) - if (!res?.[0]?.list?.length) throw new Error("Cannot fetch data") return res.map(k => k.list).flat().map(k => ({ id: k.data.id, title: k.data.title, @@ -20,5 +19,5 @@ export default defineSource(async () => { date: tranformToUTC(k.data.publishTime), }, url: k.data.url, - })).sort((m, n) => m.extra.date < n.extra.date ? 1 : -1).slice(0, 30) + })).sort((m, n) => m.extra.date < n.extra.date ? 1 : -1) }) diff --git a/server/sources/cls/index.ts b/server/sources/cls/index.ts new file mode 100644 index 0000000..5846561 --- /dev/null +++ b/server/sources/cls/index.ts @@ -0,0 +1,68 @@ +import { getSearchParams } from "./utils" + +interface Item { + id: number + title?: string + brief: string + shareurl: string + // need *1000 + ctime: number + // 1 + is_ad: number +} +interface TelegraphRes { + data: { + roll_data: Item[] + } +} + +interface Depthes { + data: { + top_article: Item[] + depth_list: Item[] + } +} + +const depth = defineSource(async () => { + const apiUrl = `https://www.cls.cn/v3/depth/home/assembled/1000` + const res: Depthes = await $fetch(apiUrl, { + query: await getSearchParams(), + }) + return res.data.depth_list.sort((m, n) => n.ctime - m.ctime).map((k) => { + return { + id: k.id, + title: k.title || k.brief, + mobileUrl: k.shareurl, + extra: { + date: k.ctime * 1000, + }, + url: `https://www.cls.cn/detail/${k.id}`, + } + }) +}) + +// hot 失效 + +const telegraph = defineSource(async () => { + const apiUrl = `https://www.cls.cn/nodeapi/updateTelegraphList` + const res: TelegraphRes = await $fetch(apiUrl, { + query: await getSearchParams({ }), + }) + return res.data.roll_data.filter(k => !k.is_ad).map((k) => { + return { + id: k.id, + title: k.title || k.brief, + mobileUrl: k.shareurl, + extra: { + date: k.ctime * 1000, + }, + url: `https://www.cls.cn/detail/${k.id}`, + } + }) +}) + +export default defineSource({ + "cls": telegraph, + "cls-telegraph": telegraph, + "cls-depth": depth, +}) diff --git a/server/sources/cls/utils.ts b/server/sources/cls/utils.ts new file mode 100644 index 0000000..f12d697 --- /dev/null +++ b/server/sources/cls/utils.ts @@ -0,0 +1,13 @@ +// https://github.com/DIYgod/RSSHub/blob/master/lib/routes/cls/utils.ts +const params = { + appName: "CailianpressWeb", + os: "web", + sv: "7.7.5", +} + +export async function getSearchParams(moreParams?: any) { + const searchParams = new URLSearchParams({ ...params, ...moreParams }) + searchParams.sort() + searchParams.append("sign", await md5(await myCrypto(searchParams.toString(), "SHA-1"))) + return searchParams +} diff --git a/server/sources/coolapk/index.ts b/server/sources/coolapk/index.ts index 331b83f..293b4c1 100644 --- a/server/sources/coolapk/index.ts +++ b/server/sources/coolapk/index.ts @@ -23,9 +23,9 @@ interface Res { export default defineSource(async () => { const url = "https://api.coolapk.com/v6/page/dataList?url=%2Ffeed%2FstatList%3FcacheExpires%3D300%26statType%3Dday%26sortField%3Ddetailnum%26title%3D%E4%BB%8A%E6%97%A5%E7%83%AD%E9%97%A8&title=%E4%BB%8A%E6%97%A5%E7%83%AD%E9%97%A8&subTitle=&page=1" const r: Res = await $fetch(url, { - headers: genHeaders(), + headers: await genHeaders(), }) - if (!r.data || r.data.length === 0) throw new Error("Failed to fetch") + if (!r.data.length) throw new Error("Failed to fetch") return r.data.filter(k => k.id).map(i => ({ id: i.id, title: i.editor_title || load(i.message).text().split("\n")[0], diff --git a/server/sources/coolapk/utils.ts b/server/sources/coolapk/utils.ts index 62bbc2d..c315dc5 100644 --- a/server/sources/coolapk/utils.ts +++ b/server/sources/coolapk/utils.ts @@ -1,6 +1,5 @@ // https://github.com/DIYgod/RSSHub/blob/master/lib/routes/coolapk/utils.ts import { Buffer } from "node:buffer" -import md5 from "md5" function getRandomDEVICE_ID() { const r = [10, 6, 6, 6, 14] @@ -8,22 +7,22 @@ function getRandomDEVICE_ID() { return id.join("-") } -function get_app_token() { +async function get_app_token() { const DEVICE_ID = getRandomDEVICE_ID() const now = Math.round(Date.now() / 1000) const hex_now = `0x${now.toString(16)}` - const md5_now = md5(now.toString()) + const md5_now = await md5(now.toString()) const s = `token://com.coolapk.market/c67ef5943784d09750dcfbb31020f0ab?${md5_now}$${DEVICE_ID}&com.coolapk.market` - const md5_s = md5(Buffer.from(s).toString("base64")) + const md5_s = await md5(Buffer.from(s).toString("base64")) const token = md5_s + DEVICE_ID + hex_now return token } -export function genHeaders() { +export async function genHeaders() { return { "X-Requested-With": "XMLHttpRequest", "X-App-Id": "com.coolapk.market", - "X-App-Token": get_app_token(), + "X-App-Token": await get_app_token(), "X-Sdk-Int": "29", "X-Sdk-Locale": "zh-CN", "X-App-Version": "11.0", diff --git a/server/sources/douyin.ts b/server/sources/douyin.ts index 979bf52..c559d6a 100644 --- a/server/sources/douyin.ts +++ b/server/sources/douyin.ts @@ -1,6 +1,6 @@ interface Res { - data?: { - word_list?: { + data: { + word_list: { sentence_id: string word: string event_time: string @@ -33,16 +33,11 @@ export default defineSource(async () => { Cookie: `passport_csrf_token=${cookie}`, }, }) - if (!res?.data?.word_list || res.data.word_list.length === 0) throw new Error("Cannot fetch data") return res.data.word_list - .slice(0, 30) .map((k) => { return { id: k.sentence_id, title: k.word, - extra: { - info: k.hot_value, - }, url: `https://www.douyin.com/hot/${k.sentence_id}`, } }) diff --git a/server/sources/index.ts b/server/sources/index.ts index ac0d4b6..e473fec 100644 --- a/server/sources/index.ts +++ b/server/sources/index.ts @@ -1,4 +1,4 @@ -import type { SourceID } from "@shared/types" +import type { DisabledSourceID, SourceID } from "@shared/types" import weibo from "./weibo" import zaobao from "./zaobao" import v2ex from "./v2ex" @@ -6,11 +6,12 @@ import ithome from "./ithome" import zhihu from "./zhihu" import cankaoxiaoxi from "./cankaoxiaoxi" import coolapk from "./coolapk" -import sputniknewscn from "./sputniknewscn" import kr36 from "./36kr" import wallstreetcn from "./wallstreetcn" import douyin from "./douyin" import toutiao from "./toutiao" +import cls from "./cls" +import sputniknewscn from "./sputniknewscn" import type { SourceGetter } from "#/types" export const sourcesGetters = { @@ -22,8 +23,9 @@ export const sourcesGetters = { coolapk, cankaoxiaoxi, sputniknewscn, - wallstreetcn, + ...wallstreetcn, douyin, + ...cls, toutiao, ...kr36, -} as Record +} as Record & Partial> diff --git a/server/sources/ithome.ts b/server/sources/ithome.ts index 2c87acd..6269412 100644 --- a/server/sources/ithome.ts +++ b/server/sources/ithome.ts @@ -28,5 +28,4 @@ export default defineSource(async () => { } }) return news.sort((m, n) => n.extra!.date > m.extra!.date ? 1 : -1) - .slice(0, 30) }) diff --git a/server/sources/sputniknewscn.ts b/server/sources/sputniknewscn.ts index 70b4ec9..dce7d30 100644 --- a/server/sources/sputniknewscn.ts +++ b/server/sources/sputniknewscn.ts @@ -1,9 +1,8 @@ import * as cheerio from "cheerio" import type { NewsItem } from "@shared/types" -import { $fetch } from "ofetch" export default defineSource(async () => { - const response = await $fetch("https://sputniknews.cn/services/widget/lenta/") + const response: any = await $fetch("https://sputniknews.cn/services/widget/lenta/") const $ = cheerio.load(response) const $items = $(".lenta__item") const news: NewsItem[] = [] @@ -24,5 +23,5 @@ export default defineSource(async () => { }) } }) - return news.slice(0, 30) + return news }) diff --git a/server/sources/toutiao.ts b/server/sources/toutiao.ts index 28d4d4c..176071f 100644 --- a/server/sources/toutiao.ts +++ b/server/sources/toutiao.ts @@ -1,5 +1,5 @@ interface Res { - data?: { + data: { ClusterIdStr: string Title: string HotValue: string @@ -12,16 +12,11 @@ interface Res { export default defineSource(async () => { const url = "https://www.toutiao.com/hot-event/hot-board/?origin=toutiao_pc" const res: Res = await $fetch(url) - if (!res.data || res.data.length === 0) throw new Error("Cannot fetch data") return res.data - .slice(0, 30) .map((k) => { return { id: k.ClusterIdStr, title: k.Title, - extra: { - info: k.HotValue, - }, url: `https://www.toutiao.com/trending/${k.ClusterIdStr}/`, } }) diff --git a/server/sources/v2ex.ts b/server/sources/v2ex.ts index cc3dd7e..fe59716 100644 --- a/server/sources/v2ex.ts +++ b/server/sources/v2ex.ts @@ -18,7 +18,6 @@ interface Res { const share = defineSource(async () => { const res = await Promise.all(["create", "ideas", "programmer", "share"].map(k => $fetch(`https://www.v2ex.com/feed/${k}.json`) as Promise< Res>)) - if (!res?.[0]?.items?.length) throw new Error("Cannot fetch data") return res.map(k => k.items).flat().map(k => ({ id: k.id, title: k.title, diff --git a/server/sources/wallstreetcn.ts b/server/sources/wallstreetcn.ts index 629d1ff..c05e5ed 100644 --- a/server/sources/wallstreetcn.ts +++ b/server/sources/wallstreetcn.ts @@ -1,33 +1,87 @@ -interface Res { +interface Item { + uri: string + id: number + title?: string + // ad + resource_type?: string + content_text: string + content_short: string + display_time: number + type?: string +} +interface LiveRes { + data: { + items: Item[] + } +} + +interface NewsRes { data: { items: { - uri: string - id: number - title?: string - content_text: string - display_time: number + resource: Item }[] } } -// https://github.com/DIYgod/RSSHub/blob/master/lib/routes/wallstreetcn/live.ts -export default defineSource(async () => { - const category = "global" - const apiRootUrl = "https://api-one.wallstcn.com" - const apiUrl = `${apiRootUrl}/apiv1/content/lives?channel=${category}-channel&limit=30` +interface HotRes { + data: { + day_items: Item[] + } +} - const res: Res = await $fetch(apiUrl) - if (!res?.data?.items || res.data.items.length === 0) throw new Error("Cannot fetch data") +// https://github.com/DIYgod/RSSHub/blob/master/lib/routes/wallstreetcn/live.ts +const live = defineSource(async () => { + const apiUrl = `https://api-one.wallstcn.com/apiv1/content/lives?channel=global-channel&limit=30` + + const res: LiveRes = await $fetch(apiUrl) return res.data.items - .slice(0, 30) .map((k) => { return { id: k.id, title: k.title || k.content_text, extra: { - date: new Date(k.display_time * 1000).getTime(), + date: k.display_time * 1000, }, url: k.uri, } }) }) + +const news = defineSource(async () => { + const apiUrl = `https://api-one.wallstcn.com/apiv1/content/information-flow?channel=global-channel&accept=article&limit=30` + + const res: NewsRes = await $fetch(apiUrl) + return res.data.items + .filter(k => k.resource.resource_type !== "ad" && k.resource.type !== "live") + .map(({ resource: h }) => { + return { + id: h.id, + title: h.title || h.content_short, + extra: { + date: h.display_time * 1000, + }, + url: h.uri, + } + }) +}) + +const hot = defineSource(async () => { + const apiUrl = `https://api-one.wallstcn.com/apiv1/content/articles/hot?period=all` + + const res: HotRes = await $fetch(apiUrl) + return res.data.day_items + .map((h) => { + return { + id: h.id, + title: h.title!, + url: h.uri, + } + }) +}) + +export default defineSource({ + "wallstreetcn": live, + "wallstreetcn-quick": live, + "wallstreetcn-news": news, + "wallstreetcn-hot": hot, +}) diff --git a/server/sources/weibo.ts b/server/sources/weibo.ts index f59ebc1..43a85c3 100644 --- a/server/sources/weibo.ts +++ b/server/sources/weibo.ts @@ -28,10 +28,8 @@ interface Res { export default defineSource(async () => { const url = "https://weibo.com/ajax/side/hotSearch" const res: Res = await $fetch(url) - if (!res.ok || res.data.realtime.length === 0) throw new Error("Cannot fetch data") return res.data.realtime .filter(k => !k.is_ad) - .slice(0, 30) .map((k) => { const keyword = k.word_scheme ? k.word_scheme : `#${k.word}#` return { diff --git a/server/sources/zaobao.ts b/server/sources/zaobao.ts index b73eb72..f0531d2 100644 --- a/server/sources/zaobao.ts +++ b/server/sources/zaobao.ts @@ -31,5 +31,4 @@ export default defineSource(async () => { } }) return news.sort((m, n) => n.extra!.date > m.extra!.date ? 1 : -1) - .slice(0, 30) }) diff --git a/server/sources/zhihu.ts b/server/sources/zhihu.ts index c998945..b76f390 100644 --- a/server/sources/zhihu.ts +++ b/server/sources/zhihu.ts @@ -22,7 +22,6 @@ interface Res { export default defineSource(async () => { const url = "https://www.zhihu.com/api/v3/feed/topstory/hot-lists/total?limit=20&desktop=true" const res: Res = await $fetch(url) - if (!res.data || res.data.length === 0) throw new Error("Cannot fetch data") return res.data .slice(0, 30) .map((k) => { diff --git a/server/utils/crypto.ts b/server/utils/crypto.ts new file mode 100644 index 0000000..23721b6 --- /dev/null +++ b/server/utils/crypto.ts @@ -0,0 +1,24 @@ +import _md5 from "md5" +import { subtle as _ } from "uncrypto" + +type T = typeof crypto.subtle +const subtle: T = _ + +export async function md5(s: string) { + try { + // https://developers.cloudflare.com/workers/runtime-apis/web-crypto/ + // cloudflare worker support md5 + return await myCrypto(s, "MD5") + } catch { + return _md5(s) + } +} + +type Algorithm = "MD5" | "SHA-1" | "SHA-256" | "SHA-384" | "SHA-512" +export async function myCrypto(s: string, algorithm: Algorithm) { + const sUint8 = new TextEncoder().encode(s) + const hashBuffer = await subtle.digest(algorithm, sUint8) + const hashArray = Array.from(new Uint8Array(hashBuffer)) + const hashHex = hashArray.map(b => b.toString(16).padStart(2, "0")).join("") + return hashHex +} diff --git a/server/utils/source.ts b/server/utils/source.ts index 99a6fa7..aca44ea 100644 --- a/server/utils/source.ts +++ b/server/utils/source.ts @@ -1,8 +1,8 @@ -import type { SourceID } from "@shared/types" +import type { AllSourceID, SourceID } from "@shared/types" import defu from "defu" import type { FallbackResponse, RSSHubOption, RSSHubInfo as RSSHubResponse, SourceGetter, SourceOption } from "#/types" -type X = SourceGetter | Partial> +type X = SourceGetter | Partial> export function defineSource(source: T): T { return source } diff --git a/shared/metadata.ts b/shared/metadata.ts index d667ab1..ea01431 100644 --- a/shared/metadata.ts +++ b/shared/metadata.ts @@ -19,7 +19,7 @@ const originMetadata: Metadata = { }, finance: { name: "财经", - sources: ["wallstreetcn", "36kr-quick"], + sources: ["cls-telegraph", "cls-depth", "wallstreetcn", "wallstreetcn-hot", "wallstreetcn-news"], }, focus: { name: "关注", diff --git a/shared/sources.ts b/shared/sources.ts index 2064f4f..e59c31c 100644 --- a/shared/sources.ts +++ b/shared/sources.ts @@ -52,16 +52,30 @@ export const originSources = { }, "wallstreetcn": { name: "华尔街见闻", - interval: Time.Fast, - type: "realtime", color: "blue", home: "https://wallstreetcn.com/", - title: "快讯", + sub: { + quick: { + type: "realtime", + interval: Time.Fast, + title: "实时快讯", + }, + news: { + title: "最新资讯", + interval: Time.Common, + }, + hot: { + title: "最热文章", + type: "hottest", + interval: Time.Common, + }, + }, }, "36kr": { name: "36氪", type: "realtime", color: "blue", + disable: true, home: "https://36kr.com", sub: { quick: { @@ -115,6 +129,22 @@ export const originSources = { interval: Time.Common, home: "https://china.cankaoxiaoxi.com", }, + "cls": { + name: "财联社", + color: "red", + home: "https://www.cls.cn", + sub: { + telegraph: { + title: "电报", + interval: Time.Fast, + type: "realtime", + }, + depth: { + title: "深度头条", + interval: Time.Common, + }, + }, + }, } as const satisfies Record export const sources = genSources() diff --git a/shared/types.ts b/shared/types.ts index 474f1fa..7fd27ce 100644 --- a/shared/types.ts +++ b/shared/types.ts @@ -15,6 +15,15 @@ export type SourceID = { }[keyof SubSource] | Key : Key; }[MainSourceID] +export type AllSourceID = { + [Key in MainSourceID]: ConstSources[Key] extends { sub?: infer SubSource } ? keyof { + // @ts-expect-error >_< + [SubKey in keyof SubSource as `${Key}-${SubKey}`]: never + } | Key : Key +}[MainSourceID] + +export type DisabledSourceID = Exclude + export type ColumnID = (typeof columnIds)[number] export type Metadata = Record diff --git a/vite.config.ts b/vite.config.ts index c5ce59c..e161928 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -74,6 +74,7 @@ export default defineConfig({ experimental: { database: true, }, + sourceMap: false, database: { default: { connector: isCF ? "cloudflare-d1" : "sqlite",