Files
moyosapp_beta.0.0.3/scripts/inventroy.ts
2026-01-15 16:19:14 +02:00

207 lines
6.9 KiB
TypeScript

#!/usr/bin/env tsx
/**
* Scans the repo and writes machine-usable facts.json to conductor/artifacts.
* No code execution; text-only heuristics. Safe for CI.
*/
import fg from "fast-glob";
import { promises as fs } from "fs";
const readText = async (p: string) => {
try {
return await fs.readFile(p, "utf8");
} catch {
return "";
}
};
const has = (s: string, ...needles: string[]) =>
needles.every((n) => s.toLowerCase().includes(n.toLowerCase()));
(async () => {
const out = "conductor/artifacts/facts.json";
const files = await fg(
[
"app/**/*",
"src/**/*",
"components/**/*",
"lib/**/*",
"services/**/*",
"public/**/*",
"next.config.*",
"proxy.ts",
"middleware.ts",
"package.json",
"prisma/**/*",
"conductor/**/*",
"gemini.md",
],
{ dot: true }
);
const textByFile = await Promise.all(files.map(readText));
const joined = textByFile.join("\n");
const findOne = async (globs: string[]) =>
(await fg(globs, { dot: true }))[0];
const nextConfigPath = await findOne(["next.config.ts", "next.config.js"]);
const nextConfig = nextConfigPath ? await readText(nextConfigPath) : "";
const facts = {
timestamp: new Date().toISOString(),
files,
next: {
hasAppRouter: files.some(
(f) =>
/^app\/layout\.(t|j)sx$/.test(f) ||
/^src\/app\/layout\.(t|j)sx$/.test(f)
),
hasProxyTs: !!(await findOne(["proxy.ts", "src/proxy.ts"])),
hasMiddlewareTs: !!(await findOne([
"middleware.ts",
"src/middleware.ts",
])),
nextConfigPath,
permissionsPolicy: (nextConfig.match(
/Permissions-Policy[^"'\n]*["'`](.*)["'`]/
) || [, ""])[1],
hasHSTS: nextConfig.includes("Strict-Transport-Security"),
hasCOOP: nextConfig.includes("Cross-Origin-Opener-Policy"),
hasCOEP:
nextConfig.includes("Cross-Origin-Embedder-Policy") ||
nextConfig.includes("Cross-Origin-Resource-Policy"),
hasCORP: nextConfig.includes("Cross-Origin-Resource-Policy"),
},
security: {
cspMentioned: has(joined, "content-security-policy", "csp") || false,
},
auth: {
hasInviteRoute: files.some(
(f) =>
/app\/invite\/\[code]\/page\.(t|j)sx$/.test(f) ||
/app\/.*invite.*\/page\.(t|j)sx$/.test(f)
),
hasOtpLogic:
/otp/i.test(joined) || /one[- ]?time[- ]?password/i.test(joined),
otpWindow5mMentioned: /5 ?min|300000/.test(joined),
hasTrustedDeviceLogic:
/trusted device/i.test(joined) || /trustedDevices/.test(joined),
trustedSessionThroughMar2_2026: /Mar(ch)? ?2,? ?2026|2026-03-02/.test(
joined
),
},
geofence: {
mentioned: /geofence|allowlist|allowed countries/i.test(joined),
allowlistCountries: [
"US",
"AU",
"PG",
"CA",
"GB",
"ZW",
"ZM",
"ZA",
].filter((c) => new RegExp(`\\b${c}\\b`).test(joined)),
hasGuidancePage: /guidance|vpn|allowed regions/i.test(joined),
},
rsvp: {
hasRsvpRoute: files.some((f) =>
/app\/\(auth\)\/rsvp\/page\.(t|j)sx$/.test(f)
),
couplePrefillMentioned: /couple|primary.*secondary|prefill/i.test(joined),
lockDateJan31_2026: /Jan(uary)? ?31,? ?2026|2026-01-31/.test(joined),
adminOverrideAudited: /override|audit/i.test(joined),
},
guestbook: {
hasGuestbookRoute: files.some((f) =>
/app\/\(auth\)\/dashboard\/guestbook\/page\.(t|j)sx$/.test(f)
),
textAudioVideo: /text.*audio.*video|audio.*video.*text/i.test(joined),
videoMax120s: /120 ?s|120 seconds|2 ?min/i.test(joined),
audioMax180s: /180 ?s|180 seconds|3 ?min/i.test(joined),
hasModerationQueue: /moderation|approve|hide/i.test(joined),
},
gallery: {
hasGalleryRoute: files.some((f) =>
/app\/\(auth\)\/dashboard\/gallery\/page\.(t|j)sx$/.test(f)
),
hasQrUpload: /qr|scan/i.test(joined),
hasEditor: /react-easy-crop|canvas|OffscreenCanvas|WebGL|editor/i.test(
joined
),
editorPresets5:
/Garden Soft|Ivory Film|Dusk Glow|Classic Noir|Vivid Bloom/i.test(
joined
),
editorAdjustments:
/crop|rotate|brightness|contrast|saturation|vibrance|sharpen|vignette|grain|blur/i.test(
joined
),
downscale2048: /2048px|downscale|resize/i.test(joined),
feeds: ["Latest", "Highlights", "Mine", "By Guest"].filter((n) =>
joined.includes(n)
),
hasModeration: /moderation|approve|hide/i.test(joined),
hasSlideshow: /slideshow|mosaic/i.test(joined),
tableBadges: /table badge|table QR/i.test(joined),
},
music: {
appleMusicMentioned: /Apple Music|MusicKit|music\.apple/i.test(joined),
top25Mentioned: /Top ?25/i.test(joined),
previewPlaybackMentioned: /preview|30 ?s|audio preview/i.test(joined),
perInviteQuotaMentioned: /quota|per[- ]invite|limit/i.test(joined),
dedupeMentioned: /dedupe|duplicate/i.test(joined),
},
sections: {
hasWeddingParty:
files.some((f) => /wedding[-]?party/i.test(f)) ||
/Wedding Party/i.test(joined),
hasTribute:
files.some((f) =>
/app\/\(auth\)\/dashboard\/tribute\/page\.(t|j)sx$/.test(f)
) || /Tribute/i.test(joined),
tributeMemorialStylingMentioned:
/ivory|charcoal|gold|candle|memorial/i.test(joined),
hasRegistry: /registry/i.test(joined),
hasVenue: /venue/i.test(joined),
hasWeather: /weather/i.test(joined),
hasTraffic: /traffic/i.test(joined),
hasDirectionsAndUber: /Apple Maps|Google Maps|Waze|Uber/i.test(joined),
hasProfileWhosWho: /Who'?s Who|guest-directory|profile consent/i.test(
joined
),
},
admin: {
shadcnMentioned: /shadcn|@\/components\/ui/.test(joined),
hasModerationQueues: /moderation queue|approve|hide/i.test(joined),
csvImportExport: /CSV|import|export/i.test(joined),
deviceManagement: /trusted device|replace device/i.test(joined),
},
media: {
ffmpegMentioned: /ffmpeg/i.test(joined),
hlsMentioned: /HLS|m3u8/i.test(joined),
aacOrOpusMentioned: /AAC|Opus/i.test(joined),
thumbnailsOrWaveformsMentioned: /thumbnail|poster|waveform/i.test(joined),
},
pwa: {
hasManifest: !!(await findOne([
"public/manifest.webmanifest",
"public/manifest.json",
])),
hasServiceWorker: !!(await findOne([
"public/service-worker.js",
"public/sw.js",
])),
},
observability: {
auditLogMentioned: /AuditLog/i.test(joined),
accessEventMentioned: /AccessEvent/i.test(joined),
analyticsEventsMentioned: /analytics|event map/i.test(joined),
o11yOrTracingMentioned: /OpenTelemetry|trace|metrics|logs/i.test(joined),
},
};
await fs.mkdir("conductor/artifacts", { recursive: true });
await fs.writeFile(out, JSON.stringify(facts, null, 2), "utf8");
console.log(`✅ wrote ${out}`);
})();