c0py: initial scaffolding for website registry tool
CI (SIAX Cloud) / security (push) Successful in 12s
CI (SIAX Cloud) / contracts (push) Failing after 12s
CI (SIAX Cloud) / quality (push) Failing after 8s
Deploy to Coolify / deploy (push) Failing after 2s

This commit is contained in:
2026-09-16 13:15:21 +02:00
commit e6cc719f37
58 changed files with 1131 additions and 0 deletions
@@ -0,0 +1,39 @@
import type { Page } from "@siax/c0py-types";
export interface AnalysisResult {
totalPages: number;
uniqueDomains: number;
avgStatusCode: number;
statusCodes: Record<number, number>;
contentTypes: Record<string, number>;
hasBrokenLinks: boolean;
brokenLinks: number;
}
export function analyzePages(pages: Page[]): AnalysisResult {
const statusCodes: Record<number, number> = {};
const contentTypes: Record<string, number> = {};
let brokenLinks = 0;
for (const page of pages) {
statusCodes[page.statusCode] = (statusCodes[page.statusCode] ?? 0) + 1;
const ct = page.contentType?.split(";")[0].trim() ?? "unknown";
contentTypes[ct] = (contentTypes[ct] ?? 0) + 1;
if (page.statusCode >= 400) brokenLinks++;
}
const avgStatusCode =
pages.length > 0
? pages.reduce((sum, p) => sum + p.statusCode, 0) / pages.length
: 0;
return {
totalPages: pages.length,
uniqueDomains: new Set(pages.map((p) => new URL(p.url).host)).size,
avgStatusCode: Math.round(avgStatusCode * 100) / 100,
statusCodes,
contentTypes,
hasBrokenLinks: brokenLinks > 0,
brokenLinks,
};
}
@@ -0,0 +1,31 @@
import type { Page, Registry, ScanRun } from "@siax/c0py-types";
import type { CrawledPage } from "./types";
export function assembleRegistry(
url: string,
name: string,
crawled: CrawledPage[]
): { registry: Registry; pages: Page[] } {
const registry: Registry = {
id: crypto.randomUUID(),
url,
name,
createdAt: new Date(),
updatedAt: new Date(),
};
const pages: Page[] = crawled.map((c) => ({
id: crypto.randomUUID(),
registryId: registry.id,
url: c.url,
path: c.path,
title: c.title,
description: c.description,
statusCode: c.statusCode,
contentType: c.contentType,
discoveredAt: new Date(),
analysis: null,
}));
return { registry, pages };
}
+15
View File
@@ -0,0 +1,15 @@
export interface CrawlOptions {
url: string;
maxPages: number;
timeoutMs: number;
}
export interface CrawledPage {
url: string;
path: string;
title: string | null;
description: string | null;
statusCode: number;
contentType: string | null;
links: string[];
}