diff --git a/scripts/discover-listing-oauth-metadata.ts b/scripts/discover-listing-oauth-metadata.ts index abfd5ab..dd99583 100644 --- a/scripts/discover-listing-oauth-metadata.ts +++ b/scripts/discover-listing-oauth-metadata.ts @@ -37,12 +37,20 @@ * If that misses a listing, re-run without `--no-playwright` for Playwright + optional manual steps. */ import "dotenv/config"; -import * as readline from "node:readline/promises"; -import { stdin as input, stdout as output } from "node:process"; -import * as schema from "#/db/schema"; import type { Database } from "#/db/index.server"; +import type { AuthorizationPageProbeAttempt } from "#/lib/oauth-authorization-page-discovery"; import type { StoreListingOauthDiscoveryDetail } from "#/lib/oauth-listing-oauth-discovery.types"; + +import * as schema from "#/db/schema"; +import { + oauthAuthorizationPageProbeTargets, + probeOAuthClientMetadataFromAuthorizationServerPage, +} from "#/lib/oauth-authorization-page-discovery"; +import { + probeOAuthListingAuth, + tryResolveOAuthClientMetadataUrlFast, +} from "#/lib/oauth-listing-auth-probe"; import { attachClientMetadataCapture, collectLoginLinkCandidates, @@ -51,24 +59,18 @@ import { readAuthHintsFromBody, tryBlueskyishIdentifierLogin, } from "#/lib/oauth-listing-playwright-discovery"; -import { - probeOAuthListingAuth, - tryResolveOAuthClientMetadataUrlFast, -} from "#/lib/oauth-listing-auth-probe"; -import type { AuthorizationPageProbeAttempt } from "#/lib/oauth-authorization-page-discovery"; -import { - oauthAuthorizationPageProbeTargets, - probeOAuthClientMetadataFromAuthorizationServerPage, -} from "#/lib/oauth-authorization-page-discovery"; import { sqlCategorySlugsHasProtocolBrowseableSegment } from "#/lib/product-claim-eligibility"; import { and, asc, eq, isNotNull, not, sql } from "drizzle-orm"; +import { stdin as input, stdout as output } from "node:process"; +import * as readline from "node:readline/promises"; + +import type { SkippedListingReason } from "./oauth-discovery-local-progress"; import { defaultOAuthDiscoveryProgressPath, isSlugInLocalSkips, loadLocalProgress, recordSkippedListing, - type SkippedListingReason, } from "./oauth-discovery-local-progress"; function ts(): string { @@ -125,7 +127,7 @@ async function saveLocalSkip(args: { slug: args.listing.slug, skippedAt: new Date().toISOString(), reason: args.reason, - ...(args.note !== undefined ? { note: args.note } : {}), + ...(args.note === undefined ? {} : { note: args.note }), }); log("local_progress_saved_skip", { slug: args.listing.slug, @@ -134,7 +136,7 @@ async function saveLocalSkip(args: { }); } -async function upsertDiscovery(input: { +async function upsertDiscovery(opts: { db: Database; listing: ListingRow; clientMetadataUrl: string | null; @@ -146,22 +148,22 @@ async function upsertDiscovery(input: { }) { const now = new Date(); const row = { - storeListingId: input.listing.id, - slug: input.listing.slug, - clientMetadataUrl: input.clientMetadataUrl, - authMethod: input.authMethod, - resolution: input.resolution, - loginPageUrl: input.loginPageUrl, - detailJson: input.detailJson, + storeListingId: opts.listing.id, + slug: opts.listing.slug, + clientMetadataUrl: opts.clientMetadataUrl, + authMethod: opts.authMethod, + resolution: opts.resolution, + loginPageUrl: opts.loginPageUrl, + detailJson: opts.detailJson, updatedAt: now, }; - if (input.dryRun) { + if (opts.dryRun) { log("dry_run_upsert_discovery", row); return; } - await input.db + await opts.db .insert(schema.storeListingOauthDiscovery) .values({ ...row, @@ -415,7 +417,7 @@ async function runPlaywrightWithManual(args: { } const onProg = (event: string, data?: Record) => - log(event, { slug: args.listing.slug, ...(data ?? {}) }); + log(event, { slug: args.listing.slug, ...data }); const attempts: Array = []; let metaUrl: string | null = null; diff --git a/scripts/oauth-discovery-local-progress.ts b/scripts/oauth-discovery-local-progress.ts index ab068e3..d92d160 100644 --- a/scripts/oauth-discovery-local-progress.ts +++ b/scripts/oauth-discovery-local-progress.ts @@ -49,10 +49,10 @@ export async function loadLocalProgress( ? (o.skipped as Record) : {}; return { version: PROGRESS_VERSION, skipped }; - } catch (e: unknown) { - const err = e as NodeJS.ErrnoException; + } catch (error: unknown) { + const err = error as NodeJS.ErrnoException; if (err.code === "ENOENT") return emptyProgress(); - throw e; + throw error; } } diff --git a/scripts/sync-listing-oauth-probes.ts b/scripts/sync-listing-oauth-probes.ts index bad96a6..8a17e8f 100644 --- a/scripts/sync-listing-oauth-probes.ts +++ b/scripts/sync-listing-oauth-probes.ts @@ -300,21 +300,23 @@ async function main() { : [storefrontUrl]; try { - let report: Awaited>; + let result: + | Awaited> + | undefined; let lastError: unknown; for (const probeUrl of orderedProbeUrls) { try { - report = await probeOAuthListingAuth(probeUrl); + result = await probeOAuthListingAuth(probeUrl); lastError = undefined; break; - } catch (e) { - lastError = e; + } catch (error) { + lastError = error; } } - if (lastError !== undefined) { + if (result === undefined) { throw lastError; } - await persistCompleted(row, report!); + await persistCompleted(row, result); } catch (error) { failed++; const message = error instanceof Error ? error.message : String(error); @@ -329,11 +331,7 @@ async function main() { ? { discoveryClientMetadataUrl: fallbackTried } : {}), }); - await persistError( - row, - orderedProbeUrls[orderedProbeUrls.length - 1] ?? null, - message, - ); + await persistError(row, orderedProbeUrls.at(-1) ?? null, message); } done++; diff --git a/src/db/schema.ts b/src/db/schema.ts index 30d07f4..b9e9b0d 100644 --- a/src/db/schema.ts +++ b/src/db/schema.ts @@ -1,7 +1,7 @@ import type { ListingLink } from "#/lib/atproto/listing-record"; import type { DirectoryOAuthLexiconHubData } from "#/lib/oauth-lexicon-hub.types"; -import type { StoreListingOauthDiscoveryDetail } from "#/lib/oauth-listing-oauth-discovery.types"; import type { OAuthAuthProbeReport } from "#/lib/oauth-listing-auth-probe"; +import type { StoreListingOauthDiscoveryDetail } from "#/lib/oauth-listing-oauth-discovery.types"; import { relations, sql } from "drizzle-orm"; import { diff --git a/src/integrations/tanstack-query/api-admin.functions.ts b/src/integrations/tanstack-query/api-admin.functions.ts index a74e31c..5d37ca6 100644 --- a/src/integrations/tanstack-query/api-admin.functions.ts +++ b/src/integrations/tanstack-query/api-admin.functions.ts @@ -894,6 +894,8 @@ const getRecentListings = createServerFn({ method: "GET" }) }); }); +const toIso = (d: Date | null) => (d ? d.toISOString() : null); + const getAdminOAuthUrlGaps = createServerFn({ method: "GET" }) .middleware([dbMiddleware, adminFnMiddleware]) .handler(async ({ context }) => { @@ -968,8 +970,6 @@ const getAdminOAuthUrlGaps = createServerFn({ method: "GET" }) .orderBy(desc(probes.probedAt), asc(listings.slug)), ]); - const toIso = (d: Date | null) => (d ? d.toISOString() : null); - return { missingClientMetadataUrl: missingRows.map((r) => ({ id: r.id, diff --git a/src/lib/oauth-authorization-page-discovery.ts b/src/lib/oauth-authorization-page-discovery.ts index e22eabf..328b20a 100644 --- a/src/lib/oauth-authorization-page-discovery.ts +++ b/src/lib/oauth-authorization-page-discovery.ts @@ -90,8 +90,7 @@ export async function probeOAuthClientMetadataFromAuthorizationServerPage( const attempts: Array = []; let clientMetadataUrl: string | null = null; - for (let i = 0; i < targets.length; i++) { - const target = targets[i]!; + for (const [i, target] of targets.entries()) { onProgress?.("authorization_page_probe_target_start", { index: i + 1, total: targets.length, diff --git a/src/lib/oauth-listing-playwright-discovery.ts b/src/lib/oauth-listing-playwright-discovery.ts index e881f08..6a31ce5 100644 --- a/src/lib/oauth-listing-playwright-discovery.ts +++ b/src/lib/oauth-listing-playwright-discovery.ts @@ -65,12 +65,11 @@ export async function readAuthHintsFromBody(page: Page): Promise<{ appPasswordMentioned: boolean; oauthMentioned: boolean; }> { - const text = ( - await page - .locator("body") - .innerText() - .catch(() => "") - ).slice(0, 150_000); + const rawText = await page + .locator("body") + .textContent() + .catch(() => ""); + const text = (rawText ?? "").slice(0, 150_000); const low = text.toLowerCase(); return { appPasswordMentioned: @@ -107,7 +106,7 @@ export async function exploreLoginEntrypoints(page: Page): Promise<{ const visited: Array = []; const candidates = await collectLoginLinkCandidates(page); const ordered = [ - ...candidates.filter(oauthishCandidate), + ...candidates.filter((c) => oauthishCandidate(c)), ...candidates.filter((c) => !oauthishCandidate(c)), ].slice(0, 6); diff --git a/src/routes/_header-layout._admin-layout.admin.oauth-url-gaps.tsx b/src/routes/_header-layout._admin-layout.admin.oauth-url-gaps.tsx index 26776f6..88822b5 100644 --- a/src/routes/_header-layout._admin-layout.admin.oauth-url-gaps.tsx +++ b/src/routes/_header-layout._admin-layout.admin.oauth-url-gaps.tsx @@ -54,28 +54,28 @@ const styles = stylex.create({ width: "100%", }, table: { - width: "100%", borderCollapse: "collapse", fontSize: "0.875rem", + width: "100%", }, th: { + textAlign: "left" as const, + whiteSpace: "nowrap" as const, borderBottomColor: uiColor.border2, borderBottomStyle: "solid", borderBottomWidth: 1, paddingBottom: verticalSpace.sm, - paddingTop: verticalSpace.sm, paddingRight: horizontalSpace.md, - textAlign: "left" as const, - whiteSpace: "nowrap" as const, + paddingTop: verticalSpace.sm, }, td: { + verticalAlign: "top" as const, borderBottomColor: uiColor.border2, borderBottomStyle: "solid", borderBottomWidth: 1, paddingBottom: verticalSpace.md, - paddingTop: verticalSpace.md, paddingRight: horizontalSpace.md, - verticalAlign: "top" as const, + paddingTop: verticalSpace.md, }, mono: { fontFamily: "ui-monospace, monospace", @@ -111,15 +111,14 @@ function AdminOAuthUrlGapsPage() { OAuth client metadata gaps - Listings with an HTTPS storefront that still need a discoverable OAuth - client-metadata URL, plus listings whose last automated probe threw an - error. Protocol directory rows and at: links are excluded - (same rules as the discovery script). + Listings with an HTTPS storefront that still need a discoverable + OAuth client-metadata URL, plus listings whose last automated probe + threw an error. Protocol directory rows and at: links + are excluded (same rules as the discovery script). - Populate URLs with{" "} - pnpm listing:oauth-discover-metadata or sync probes; see{" "} - store_listing_oauth_discovery and{" "} + Populate URLs with pnpm listing:oauth-discover-metadata{" "} + or sync probes; see store_listing_oauth_discovery and{" "} store_listing_oauth_probes. @@ -199,7 +198,9 @@ function GapTable({ > {row.name} - {row.slug} + + {row.slug} + @@ -261,7 +262,9 @@ function GapTable({ > {row.name} - {row.slug} + + {row.slug} +