1
mirror of https://github.com/jakejarvis/hoot.git synced 2025-10-18 14:24:26 -04:00

Update DNS schemas and service to use 'resolver' terminology; add retry option in Screenshot component for improved reliability

This commit is contained in:
2025-10-03 20:26:04 -04:00
parent 47d20ce007
commit c768fd1460
8 changed files with 38 additions and 14 deletions

11
codecov.yml Normal file
View File

@@ -0,0 +1,11 @@
# yaml-language-server: $schema=https://json.schemastore.org/codecov
coverage:
status:
project:
default:
target: auto
informational: true
patch:
default:
target: auto
informational: true

View File

@@ -127,7 +127,7 @@ describe("DomainReportView", () => {
expect(screen.getByText("SSL Certificates")).toBeInTheDocument();
expect(screen.getByText("HTTP Headers")).toBeInTheDocument();
// Export button enabled when all sections are settled
const exportBtn = screen.getByRole("button", { name: /Export JSON/i });
const exportBtn = screen.getByRole("button", { name: /Export/i });
expect(exportBtn).not.toBeDisabled();
});
@@ -168,7 +168,7 @@ describe("DomainReportView", () => {
},
};
render(<DomainReportView domain="loading.com" />);
const exportBtn = screen.getByRole("button", { name: /Export JSON/i });
const exportBtn = screen.getByRole("button", { name: /Export/i });
expect(exportBtn).toBeDisabled();
});
@@ -209,7 +209,7 @@ describe("DomainReportView", () => {
},
};
render(<DomainReportView domain="errors.com" />);
const exportBtn = screen.getByRole("button", { name: /Export JSON/i });
const exportBtn = screen.getByRole("button", { name: /Export/i });
expect(exportBtn).not.toBeDisabled();
});
});

View File

@@ -1,6 +1,6 @@
"use client";
import { ExternalLink, FileJson2 } from "lucide-react";
import { Download, ExternalLink } from "lucide-react";
import Link from "next/link";
import { DomainLoadingState } from "@/components/domain/domain-loading-state";
import { DomainUnregisteredState } from "@/components/domain/domain-unregistered-state";
@@ -95,8 +95,8 @@ export function DomainReportView({ domain }: { domain: string }) {
onClick={handleExportJson}
disabled={areSecondarySectionsLoading}
>
<FileJson2 />
Export JSON
<Download />
<span className="hidden sm:inline-block">Export</span>
</Button>
</div>
</div>

View File

@@ -29,6 +29,7 @@ export function Screenshot({
{ domain },
{
staleTime: 24 * 60 * 60_000, // 24h in ms
retry: 5,
enabled,
},
),

View File

@@ -187,6 +187,18 @@ export const HOSTING_PROVIDERS: Array<
category: "hosting",
rule: { kind: "headerPresent", name: "x-kinsta-cache" },
},
{
name: "Railway",
domain: "railway.app",
category: "hosting",
rule: {
any: [
{ kind: "headerPresent", name: "x-railway-request-id" },
{ kind: "headerPresent", name: "x-railway-edge" },
{ kind: "headerIncludes", name: "server", substr: "railway" },
],
},
},
{
name: "Bunny.net",
domain: "bunny.net",

View File

@@ -1,6 +1,6 @@
import { z } from "zod";
export const DnsSourceSchema = z.enum(["cloudflare", "google"]);
export const DnsResolverSchema = z.enum(["cloudflare", "google"]);
export const DnsTypeSchema = z.enum(["A", "AAAA", "MX", "TXT", "NS"]);
@@ -15,10 +15,10 @@ export const DnsRecordSchema = z.object({
export const DnsResolveResultSchema = z.object({
records: z.array(DnsRecordSchema),
source: DnsSourceSchema,
resolver: DnsResolverSchema,
});
export type DnsSource = z.infer<typeof DnsSourceSchema>;
export type DnsResolver = z.infer<typeof DnsResolverSchema>;
export type DnsType = z.infer<typeof DnsTypeSchema>;
export type DnsRecord = z.infer<typeof DnsRecordSchema>;
export type DnsResolveResult = z.infer<typeof DnsResolveResultSchema>;

View File

@@ -1,5 +1,5 @@
import { z } from "zod";
import { DnsRecordSchema, DnsSourceSchema } from "./dns";
import { DnsRecordSchema, DnsResolverSchema } from "./dns";
import { HostingSchema } from "./hosting";
import { HttpHeadersSchema } from "./http";
import { RegistrationSchema } from "./registration";
@@ -22,7 +22,7 @@ export const DomainExportSchema = z.object({
dns: z
.object({
records: z.array(DnsRecordSchema.omit({ isCloudflare: true })),
source: DnsSourceSchema,
resolver: DnsResolverSchema,
})
.nullish(),
hosting: HostingSchema.transform((h) => ({

View File

@@ -6,13 +6,13 @@ import {
type DnsRecord,
DnsRecordSchema,
type DnsResolveResult,
type DnsSource,
type DnsResolver,
type DnsType,
DnsTypeSchema,
} from "@/lib/schemas";
export type DohProvider = {
key: DnsSource;
key: DnsResolver;
buildUrl: (domain: string, type: DnsType) => URL;
headers?: Record<string, string>;
};
@@ -89,7 +89,7 @@ export async function resolveAll(domain: string): Promise<DnsResolveResult> {
provider_attempts: attemptIndex + 1,
duration_ms_by_provider: durationByProvider,
});
return { records: flat, source: provider.key } as DnsResolveResult;
return { records: flat, resolver: provider.key } as DnsResolveResult;
} catch (err) {
durationByProvider[provider.key] = Date.now() - attemptStart;
lastError = err;