diff --git a/apps/worker/src/tasks/grant-author-achievements/processor.ts b/apps/worker/src/tasks/grant-author-achievements/processor.ts index aed8c769..059819b8 100644 --- a/apps/worker/src/tasks/grant-author-achievements/processor.ts +++ b/apps/worker/src/tasks/grant-author-achievements/processor.ts @@ -31,7 +31,7 @@ export default createProcessor(Tasks.GRANT_AUTHOR_ACHIEVEMENTS, async (job) => { socials?: Record; }; const roles = meta.roles ?? []; - const githubLogin = meta.socials?.github; + const githubLogin = meta.socials?.["github"]; // ── Content stats ───────────────────────────────────────────────────────── diff --git a/apps/worker/src/tasks/sync-collection/processor.ts b/apps/worker/src/tasks/sync-collection/processor.ts index d90c15ad..620b8c91 100644 --- a/apps/worker/src/tasks/sync-collection/processor.ts +++ b/apps/worker/src/tasks/sync-collection/processor.ts @@ -188,6 +188,8 @@ export default createProcessor( .values(result) .returning({ id: collections.id }); + if (!collectionRecord) throw new Error("undefined collectionRecord"); + // Delete existing author associations for this collection await tx .delete(collectionAuthors) diff --git a/apps/worker/src/tasks/sync-post/processor.ts b/apps/worker/src/tasks/sync-post/processor.ts index 45f7b3a9..484bfcb3 100644 --- a/apps/worker/src/tasks/sync-post/processor.ts +++ b/apps/worker/src/tasks/sync-post/processor.ts @@ -177,6 +177,7 @@ export default createProcessor(Tasks.SYNC_POST, async (job, { signal }) => { .insert(postGroups) .values({}) .returning({ id: postGroups.id }); + if (!newGroup) throw new Error("undefined newGroup"); groupId = newGroup.id; } } @@ -217,6 +218,8 @@ export default createProcessor(Tasks.SYNC_POST, async (job, { signal }) => { .values(postValues) .returning({ id: posts.id }); + if (!postRecord) throw new Error("undefined postRecord"); + const authorSlugs = new Set([author, ...(parsed.authors ?? [])]); authorSlugs.forEach((authorSlug) => affectedAuthorSlugs.add(authorSlug)); diff --git a/apps/worker/src/tasks/url-metadata/data-providers/youtube.ts b/apps/worker/src/tasks/url-metadata/data-providers/youtube.ts index 60ee9dc6..1362b992 100644 --- a/apps/worker/src/tasks/url-metadata/data-providers/youtube.ts +++ b/apps/worker/src/tasks/url-metadata/data-providers/youtube.ts @@ -25,7 +25,7 @@ export async function getYouTubeOEmbedDataFromUrl( signal: AbortSignal, ): Promise { const splitPath = url.pathname.split("/").filter(Boolean); - let videoId: string; + let videoId: string | undefined; if (url.host === youtubeShortHost) { videoId = splitPath[0]; } else if (splitPath[0] === "watch") { @@ -40,10 +40,9 @@ export async function getYouTubeOEmbedDataFromUrl( // https://www.youtube.com/shorts/Fdbha07mFzo } else if (splitPath[0] === "shorts") { videoId = splitPath[1]; - } else { - return null; } + if (!videoId) return null; const youtubeUrl = `https://www.youtube.com/watch?v=${videoId}`; return await fetchAsBot({ diff --git a/apps/worker/src/tasks/url-metadata/getEmbedDataFromGist.ts b/apps/worker/src/tasks/url-metadata/getEmbedDataFromGist.ts index 91c020f2..abf86540 100644 --- a/apps/worker/src/tasks/url-metadata/getEmbedDataFromGist.ts +++ b/apps/worker/src/tasks/url-metadata/getEmbedDataFromGist.ts @@ -17,15 +17,13 @@ export async function getEmbedDataFromGist( inputUrl: URL, signal: AbortSignal, ): Promise { - let error = false; - // https://gist.github.com/crutchcorn/36fe5553219c05ea38bacf1c7396085b const gistPathParts = inputUrl.pathname.split("/").filter(Boolean); const githubUsername = gistPathParts[0]; const gistId = gistPathParts[1]; if (!githubUsername || !gistId) { console.error(`Invalid gist URL: ${inputUrl}`); - error = true; + return { error: true }; } const data = await createAppClient() @@ -114,6 +112,6 @@ export async function getEmbedDataFromGist( return { gistId, - error, + error: false, }; } diff --git a/apps/worker/src/tasks/url-metadata/getEmbedDataFromVideo.ts b/apps/worker/src/tasks/url-metadata/getEmbedDataFromVideo.ts index 1b80186c..ac9e7717 100644 --- a/apps/worker/src/tasks/url-metadata/getEmbedDataFromVideo.ts +++ b/apps/worker/src/tasks/url-metadata/getEmbedDataFromVideo.ts @@ -54,9 +54,9 @@ export async function getEmbedDataFromVideo( let embedHeight: number | undefined = undefined; if (videoData?.html) { const attributes = getIFrameAttributes(videoData.html); - if (attributes.src) embedSrc = String(attributes.src); - const width = Number(attributes.width); - const height = Number(attributes.height); + if (attributes["src"]) embedSrc = String(attributes["src"]); + const width = Number(attributes["width"]); + const height = Number(attributes["height"]); if (isFinite(width)) embedWidth = width; if (isFinite(height)) embedHeight = height; } diff --git a/apps/worker/src/tasks/url-metadata/utils/fetchPageHtml.ts b/apps/worker/src/tasks/url-metadata/utils/fetchPageHtml.ts index f7e97e51..dc8fd68a 100644 --- a/apps/worker/src/tasks/url-metadata/utils/fetchPageHtml.ts +++ b/apps/worker/src/tasks/url-metadata/utils/fetchPageHtml.ts @@ -30,9 +30,11 @@ export async function getOpenGraphImages( if (!headNode) return results; visit(headNode, { type: "element", tagName: "meta" }, (e: Element) => { - if (["twitter:image", "og:image"].includes(String(e.properties.property))) { + if ( + ["twitter:image", "og:image"].includes(String(e.properties["property"])) + ) { try { - const url = new URL(String(e.properties.content), baseUrl); + const url = new URL(String(e.properties["content"]), baseUrl); results.push(url); } catch (_e) { // ignore diff --git a/apps/worker/src/tasks/url-metadata/utils/fetchPageIcons.ts b/apps/worker/src/tasks/url-metadata/utils/fetchPageIcons.ts index 4ac4748c..159cf795 100644 --- a/apps/worker/src/tasks/url-metadata/utils/fetchPageIcons.ts +++ b/apps/worker/src/tasks/url-metadata/utils/fetchPageIcons.ts @@ -16,8 +16,8 @@ export async function fetchPageIcons( // Try getting icon from link tags first visit(headNode, { type: "element", tagName: "link" }, (node: Element) => { - const rel = String(node.properties?.rel ?? ""); - const href = String(node.properties?.href ?? ""); + const rel = String(node.properties?.["rel"] ?? ""); + const href = String(node.properties?.["href"] ?? ""); if (!rel.includes("icon")) return; try { @@ -34,11 +34,11 @@ export async function fetchPageIcons( (node) => isElement(node) && node.tagName === "link" && - String(node.properties.rel).includes("manifest"), + String(node.properties["rel"]).includes("manifest"), ); - if (manifestLink?.properties?.href) { - const manifestUrl = new URL(String(manifestLink.properties.href), src); + if (manifestLink?.properties?.["href"]) { + const manifestUrl = new URL(String(manifestLink.properties["href"]), src); const manifest = await fetchAsBot({ url: manifestUrl, method: "GET", diff --git a/apps/worker/src/tasks/url-metadata/utils/processImage.ts b/apps/worker/src/tasks/url-metadata/utils/processImage.ts index bfd88350..ffb594fb 100644 --- a/apps/worker/src/tasks/url-metadata/utils/processImage.ts +++ b/apps/worker/src/tasks/url-metadata/utils/processImage.ts @@ -297,4 +297,5 @@ export async function processImages( return result; } } + return undefined; } diff --git a/apps/worker/src/utils/extractLocale.ts b/apps/worker/src/utils/extractLocale.ts index c44a2c3e..a5870703 100644 --- a/apps/worker/src/utils/extractLocale.ts +++ b/apps/worker/src/utils/extractLocale.ts @@ -1,4 +1,4 @@ export function extractLocale(filename: string): string { const match = filename.match(/index\.([a-z]+)\.md$/); - return match ? match[1] : "en"; + return match?.[1] ?? "en"; } diff --git a/packages/bullmq/src/tasks/delete-s3-object.test.ts b/packages/bullmq/src/tasks/delete-s3-object.test.ts index f5e33aa8..d7c394d0 100644 --- a/packages/bullmq/src/tasks/delete-s3-object.test.ts +++ b/packages/bullmq/src/tasks/delete-s3-object.test.ts @@ -10,7 +10,7 @@ afterEach(() => { }); function jobIdFromCall(callIndex: number): string { - return vi.mocked(createJob).mock.calls[callIndex][1] as string; + return vi.mocked(createJob).mock.calls[callIndex]?.[1] as string; } test("reuses the same job id when lastModified is unchanged across calls", async () => { diff --git a/packages/github-api/src/getAuthorGitHubStats.ts b/packages/github-api/src/getAuthorGitHubStats.ts index a9b01e5d..bc43e516 100644 --- a/packages/github-api/src/getAuthorGitHubStats.ts +++ b/packages/github-api/src/getAuthorGitHubStats.ts @@ -52,12 +52,12 @@ export async function getAuthorGitHubStats( client: Octokit, githubLogin: string, ): Promise { - const userResult = (await client.graphql>( + const userResult = await client.graphql>( `query($login: String!) { user(login: $login) { id } }`, { login: githubLogin }, - )) as Record; + ); - const userId = userResult?.user?.id; + const userId = userResult?.["user"]?.id; if (!userId) return undefined; const response = await client.graphql(statsQuery, { diff --git a/packages/post-images/src/fetch-post-data.ts b/packages/post-images/src/fetch-post-data.ts index b8f229c2..0b30ee85 100644 --- a/packages/post-images/src/fetch-post-data.ts +++ b/packages/post-images/src/fetch-post-data.ts @@ -137,7 +137,8 @@ export async function fetchPostData( .then((json) => Value.Parse(TagsInfo, json)); const tags = (indexInfo.tags ?? []) .map((tagId) => tagsJson[tagId]) - .filter((tag) => tag?.emoji || (tag?.image && tag.shownWithBranding)) + .filter((tag) => !!tag) + .filter((tag) => tag.emoji || (tag.image && tag.shownWithBranding)) .map((tag) => ({ displayName: tag.displayName, emoji: tag.emoji, diff --git a/tsconfig.json b/tsconfig.json index 83b5b244..b94ae831 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,6 +14,8 @@ "esModuleInterop": true, "noImplicitOverride": true, "noFallthroughCasesInSwitch": true, + "noPropertyAccessFromIndexSignature": true, + "noUncheckedIndexedAccess": true, "forceConsistentCasingInFileNames": true, "allowJs": true },