feat: content engine usw

This commit is contained in:
2026-02-25 12:43:57 +01:00
parent a55a5bb834
commit 960914ebb8
21 changed files with 722 additions and 203 deletions

View File

@@ -24,5 +24,3 @@ coverage
**/.pnpm-store **/.pnpm-store
.gitea .gitea
**/.gitea **/.gitea
models
**/models

View File

@@ -1,6 +1,16 @@
FROM node:20.18-bookworm-slim AS base FROM node:20.18-bookworm-slim AS base
ENV PNPM_HOME="/pnpm" ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH" ENV PATH="$PNPM_HOME:$PATH"
RUN apt-get update && apt-get install -y \
build-essential \
python3 \
libcairo2-dev \
libpango1.0-dev \
libjpeg-dev \
libgif-dev \
librsvg2-dev \
libexpat1 \
&& rm -rf /var/lib/apt/lists/*
RUN npm install -g pnpm@10.30.1 RUN npm install -g pnpm@10.30.1
FROM base AS build FROM base AS build
@@ -13,14 +23,17 @@ RUN pnpm --filter image-service build
FROM base FROM base
WORKDIR /app WORKDIR /app
COPY --from=build /app/node_modules ./node_modules # Instead of copying node_modules which contains native C++ bindings for canvas and tfjs-node,
COPY --from=build /app/apps/image-service/node_modules ./apps/image-service/node_modules # we copy the package.json files and install natively in the final stage so the bindings are correct.
COPY --from=build /app/packages/image-processor/node_modules ./packages/image-processor/node_modules COPY package.json pnpm-workspace.yaml pnpm-lock.yaml ./
RUN mkdir -p /app/apps/image-service/dist COPY apps/image-service/package.json ./apps/image-service/package.json
COPY packages/image-processor/package.json ./packages/image-processor/package.json
RUN pnpm install --frozen-lockfile --filter image-service...
COPY --from=build /app/apps/image-service/dist ./apps/image-service/dist COPY --from=build /app/apps/image-service/dist ./apps/image-service/dist
COPY --from=build /app/apps/image-service/package.json ./apps/image-service/package.json
COPY --from=build /app/packages/image-processor/dist ./packages/image-processor/dist COPY --from=build /app/packages/image-processor/dist ./packages/image-processor/dist
COPY --from=build /app/packages/image-processor/package.json ./packages/image-processor/package.json COPY --from=build /app/packages/image-processor/models ./packages/image-processor/models
EXPOSE 8080 EXPOSE 8080
WORKDIR /app/apps/image-service WORKDIR /app/apps/image-service

View File

@@ -56,7 +56,6 @@ async function handleProcessing(url: string, options: any, reply: any) {
height, height,
format, format,
quality, quality,
openRouterApiKey: process.env.OPENROUTER_API_KEY,
}); });
reply.header("Content-Type", `image/${format}`); reply.header("Content-Type", `image/${format}`);

14
optimize-images.sh Normal file
View File

@@ -0,0 +1,14 @@
#!/bin/bash
# Ghost Image Optimizer
# Target directory for Ghost content
TARGET_DIR="/home/deploy/sites/marisas.world/content/images"
echo "Starting image optimization for $TARGET_DIR..."
# Find all original images, excluding the 'size/' directory where Ghost stores thumbnails
# Resize images larger than 2500px down to 2500px width
# Compress JPEG/PNG to 80% quality
find "$TARGET_DIR" -type d -name "size" -prune -o \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" \) -type f -exec mogrify -resize '2500x>' -quality 80 {} +
echo "Optimization complete."

View File

@@ -17,6 +17,7 @@ export interface OptimizationTask {
availableComponents?: ComponentDefinition[]; availableComponents?: ComponentDefinition[];
instructions?: string; instructions?: string;
internalLinks?: { title: string; slug: string }[]; internalLinks?: { title: string; slug: string }[];
customSources?: string[];
} }
export interface OptimizeFileOptions { export interface OptimizeFileOptions {
@@ -211,7 +212,32 @@ export class AiBlogPostOrchestrator {
console.log(`✅ Saved optimized file to: ${finalPath}`); console.log(`✅ Saved optimized file to: ${finalPath}`);
} }
private async generateVisualPrompt(content: string): Promise<string> { async generateSlug(content: string, title?: string, instructions?: string): Promise<string> {
const response = await this.openai.chat.completions.create({
model: "google/gemini-2.5-flash",
messages: [
{
role: "system",
content: `You generate SEO-optimized URL slugs for B2B blog posts based on the provided content.
Return ONLY a JSON object with a single string field "slug".
Example: {"slug": "how-to-optimize-react-performance"}
Rules: Use lowercase letters, numbers, and hyphens only. No special characters. Keep it concise (2-5 words).`,
},
{ role: "user", content: `Title: ${title || "Unknown"}\n\nContent:\n${content.slice(0, 3000)}...${instructions ? `\n\nEDITOR INSTRUCTIONS:\nPlease strictly follow these instructions from the editor when generating the slug:\n${instructions}` : ""}` },
],
response_format: { type: "json_object" },
});
try {
const parsed = JSON.parse(response.choices[0].message.content || '{"slug": ""}');
let slug = parsed.slug || "new-post";
return slug.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
} catch {
return "new-post";
}
}
public async generateVisualPrompt(content: string, instructions?: string): Promise<string> {
const response = await this.openai.chat.completions.create({ const response = await this.openai.chat.completions.create({
model: this.model, model: this.model,
messages: [ messages: [
@@ -227,7 +253,7 @@ FOCUS: The core metaphor or technical concept of the article.
Example output: "A complex network of glowing fiber optic nodes forming a recursive pyramid structure, technical blue lineart style."`, Example output: "A complex network of glowing fiber optic nodes forming a recursive pyramid structure, technical blue lineart style."`,
}, },
{ role: "user", content: content.slice(0, 5000) }, { role: "user", content: `${content.slice(0, 5000)}${instructions ? `\n\nEDITOR INSTRUCTIONS:\nPlease strictly follow these instructions from the editor when generating the visual prompt:\n${instructions}` : ""}` },
], ],
max_tokens: 100, max_tokens: 100,
}); });
@@ -303,6 +329,7 @@ Example output: "A complex network of glowing fiber optic nodes forming a recurs
); );
const realPosts = await this.researchAgent.fetchRealSocialPosts( const realPosts = await this.researchAgent.fetchRealSocialPosts(
task.content.slice(0, 500), task.content.slice(0, 500),
task.customSources
); );
socialPosts.push(...realPosts); socialPosts.push(...realPosts);
} }
@@ -470,7 +497,6 @@ BLOG POST BEST PRACTICES (MANDATORY):
- MEME DIVERSITY: Du MUSST ZWINGEND für jedes Meme (sofern passend) abwechslungsreiche Templates nutzen. Um dies zu garantieren, wurde für diesen Artikel das folgende Template ausgewählt: '${forcedMeme}'. Du MUSST EXAKT DIESES TEMPLATE NUTZEN. Versuche nicht, es durch ein Standard-Template wie 'drake' zu ersetzen! - MEME DIVERSITY: Du MUSST ZWINGEND für jedes Meme (sofern passend) abwechslungsreiche Templates nutzen. Um dies zu garantieren, wurde für diesen Artikel das folgende Template ausgewählt: '${forcedMeme}'. Du MUSST EXAKT DIESES TEMPLATE NUTZEN. Versuche nicht, es durch ein Standard-Template wie 'drake' zu ersetzen!
- Zitat-Varianten: Wenn du Organisationen oder Studien zitierst, nutze ArticleQuote (mit isCompany=true für Firmen). Für Personen lass isCompany weg. - Zitat-Varianten: Wenn du Organisationen oder Studien zitierst, nutze ArticleQuote (mit isCompany=true für Firmen). Für Personen lass isCompany weg.
- Füge zwingend ein prägnantes 'TL;DR' ganz am Anfang ein. - Füge zwingend ein prägnantes 'TL;DR' ganz am Anfang ein.
- Füge ein sauberes TableOfContents ein.
- Verwende unsere Komponenten stilvoll für Visualisierungen. - Verwende unsere Komponenten stilvoll für Visualisierungen.
- Agiere als hochprofessioneller Digital Architect und entferne alte MDX-Metadaten im Body. - Agiere als hochprofessioneller Digital Architect und entferne alte MDX-Metadaten im Body.
- Fazit: Schließe JEDEN Artikel ZWINGEND mit einem starken, klaren 'Fazit' ab. - Fazit: Schließe JEDEN Artikel ZWINGEND mit einem starken, klaren 'Fazit' ab.

View File

@@ -0,0 +1 @@
404: Not Found

View File

@@ -0,0 +1,30 @@
[
{
"weights":
[
{"name":"conv0/filters","shape":[3,3,3,16],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.009007044399485869,"min":-1.2069439495311063}},
{"name":"conv0/bias","shape":[16],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.005263455241334205,"min":-0.9211046672334858}},
{"name":"conv1/depthwise_filter","shape":[3,3,16,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.004001977630690033,"min":-0.5042491814669441}},
{"name":"conv1/pointwise_filter","shape":[1,1,16,32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.013836609615999109,"min":-1.411334180831909}},
{"name":"conv1/bias","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0015159862590771096,"min":-0.30926119685173037}},
{"name":"conv2/depthwise_filter","shape":[3,3,32,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.002666276225856706,"min":-0.317286870876948}},
{"name":"conv2/pointwise_filter","shape":[1,1,32,64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.015265831292844286,"min":-1.6792414422128714}},
{"name":"conv2/bias","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0020280554598453,"min":-0.37113414915168985}},
{"name":"conv3/depthwise_filter","shape":[3,3,64,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.006100742489683862,"min":-0.8907084034938438}},
{"name":"conv3/pointwise_filter","shape":[1,1,64,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.016276211832083907,"min":-2.0508026908425725}},
{"name":"conv3/bias","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.003394414279975143,"min":-0.7637432129944072}},
{"name":"conv4/depthwise_filter","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.006716050119961009,"min":-0.8059260143953211}},
{"name":"conv4/pointwise_filter","shape":[1,1,128,256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.021875603993733724,"min":-2.8875797271728514}},
{"name":"conv4/bias","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0041141652009066415,"min":-0.8187188749804216}},
{"name":"conv5/depthwise_filter","shape":[3,3,256,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.008423839597141042,"min":-0.9013508368940915}},
{"name":"conv5/pointwise_filter","shape":[1,1,256,512],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.030007277283014035,"min":-3.8709387695088107}},
{"name":"conv5/bias","shape":[512],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.008402082966823203,"min":-1.4871686851277068}},
{"name":"conv8/filters","shape":[1,1,512,25],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.028336129469030042,"min":-4.675461362389957}},
{"name":"conv8/bias","shape":[25],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.002268134028303857,"min":-0.41053225912299807}}
],
"paths":
[
"tiny_face_detector_model.bin"
]
}
]

View File

@@ -13,11 +13,14 @@
} }
}, },
"scripts": { "scripts": {
"build": "tsup src/index.ts --format esm --dts --clean", "build": "tsup",
"dev": "tsup src/index.ts --format esm --watch --dts", "dev": "tsup --watch",
"lint": "eslint src" "lint": "eslint src"
}, },
"dependencies": { "dependencies": {
"@tensorflow/tfjs": "^4.22.0",
"@vladmandic/face-api": "^1.7.15",
"canvas": "^3.2.1",
"sharp": "^0.33.2" "sharp": "^0.33.2"
}, },
"devDependencies": { "devDependencies": {
@@ -27,4 +30,4 @@
"tsup": "^8.3.5", "tsup": "^8.3.5",
"typescript": "^5.0.0" "typescript": "^5.0.0"
} }
} }

View File

@@ -1,11 +1,40 @@
import sharp from "sharp"; import sharp from "sharp";
import { Canvas, Image, ImageData } from "canvas";
// Use the ESM no-bundle build to avoid the default Node entrypoint
// which hardcodes require('@tensorflow/tfjs-node') and crashes in Docker.
// This build uses pure @tensorflow/tfjs (JS-only, no native C++ bindings).
// @ts-ignore - direct path import has no type declarations
import * as faceapi from "@vladmandic/face-api/dist/face-api.esm-nobundle.js";
import * as tf from "@tensorflow/tfjs";
import path from "path";
import { fileURLToPath } from "url";
// Polyfill required by face-api for Node.js
faceapi.env.monkeyPatch({ Canvas, Image, ImageData } as any);
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const MODEL_URL = path.join(__dirname, "../models");
// State flag to ensure we only load weights once
let modelsLoaded = false;
async function loadModelsOnce() {
if (modelsLoaded) return;
// Initialize pure JS CPU backend (no native bindings needed)
await tf.setBackend("cpu");
await tf.ready();
// Load the microscopic TinyFaceDetector (~190KB)
await faceapi.nets.tinyFaceDetector.loadFromDisk(MODEL_URL);
modelsLoaded = true;
}
export interface ProcessImageOptions { export interface ProcessImageOptions {
width: number; width: number;
height: number; height: number;
format?: "webp" | "jpeg" | "png" | "avif"; format?: "webp" | "jpeg" | "png" | "avif";
quality?: number; quality?: number;
openRouterApiKey?: string;
} }
/** /**
@@ -80,91 +109,6 @@ export function parseImgproxyOptions(
return options; return options;
} }
interface FaceDetection {
x: number;
y: number;
width: number;
height: number;
}
/**
* Detects faces using OpenRouter Vision API.
* Uses a small preview to save bandwidth and tokens.
*/
async function detectFacesWithCloud(
inputBuffer: Buffer,
apiKey: string,
): Promise<FaceDetection[]> {
try {
// Generate a small preview for vision API (max 512px)
const preview = await sharp(inputBuffer)
.resize(512, 512, { fit: "inside" })
.jpeg({ quality: 60 })
.toBuffer();
const base64Image = preview.toString("base64");
const response = await fetch(
"https://openrouter.ai/api/v1/chat/completions",
{
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
"HTTP-Referer": "https://mintel.me",
"X-Title": "Mintel Image Service",
},
body: JSON.stringify({
model: "google/gemini-3-flash-preview", // Fast, cheap, and supports vision
messages: [
{
role: "user",
content: [
{
type: "text",
text: 'Detect all human faces in this image. Return ONLY a JSON array of bounding boxes like: [{"x": 0.1, "y": 0.2, "width": 0.05, "height": 0.05}]. Coordinates must be normalized (0 to 1). If no faces, return [].',
},
{
type: "image_url",
image_url: {
url: `data:image/jpeg;base64,${base64Image}`,
},
},
],
},
],
response_format: { type: "json_object" },
}),
},
);
if (!response.ok) {
throw new Error(`OpenRouter API error: ${response.statusText}`);
}
const data = (await response.json()) as any;
const content = data.choices[0]?.message?.content;
if (!content) return [];
// The model might return directly or wrapped in a json field
const parsed = typeof content === "string" ? JSON.parse(content) : content;
const detections = (parsed.faces || parsed.detections || parsed) as any[];
if (!Array.isArray(detections)) return [];
return detections.map((d) => ({
x: d.x,
y: d.y,
width: d.width,
height: d.height,
}));
} catch (error) {
console.error("Cloud face detection failed:", error);
return [];
}
}
export async function processImageWithSmartCrop( export async function processImageWithSmartCrop(
inputBuffer: Buffer, inputBuffer: Buffer,
options: ProcessImageOptions, options: ProcessImageOptions,
@@ -176,32 +120,41 @@ export async function processImageWithSmartCrop(
throw new Error("Could not read image metadata"); throw new Error("Could not read image metadata");
} }
const detections = options.openRouterApiKey // Load ML models (noop if already loaded)
? await detectFacesWithCloud(inputBuffer, options.openRouterApiKey) await loadModelsOnce();
: [];
// Convert sharp image to a Node-compatible canvas Image for face-api
const jpegBuffer = await sharpImage.jpeg().toBuffer();
const img = new Image();
img.src = jpegBuffer;
const canvas = new Canvas(img.width, img.height);
const ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, img.width, img.height);
// Detect faces locally using the tiny model
// Requires explicit any cast since the types expect HTML elements in browser contexts
const detections = await faceapi.detectAllFaces(
canvas as any,
new faceapi.TinyFaceDetectorOptions(),
);
let cropPosition: "center" | "attention" | number = "attention"; // Fallback to sharp's attention if no faces
// If faces are found, calculate the bounding box containing all faces
if (detections.length > 0) { if (detections.length > 0) {
// Map normalized coordinates back to pixels // We have faces! Calculate the bounding box that contains all of them
const pixelDetections = detections.map((d) => ({
x: d.x * (metadata.width || 0),
y: d.y * (metadata.height || 0),
width: d.width * (metadata.width || 0),
height: d.height * (metadata.height || 0),
}));
let minX = metadata.width; let minX = metadata.width;
let minY = metadata.height; let minY = metadata.height;
let maxX = 0; let maxX = 0;
let maxY = 0; let maxY = 0;
for (const det of pixelDetections) { for (const det of detections) {
if (det.x < minX) minX = Math.max(0, det.x); const box = det.box;
if (det.y < minY) minY = Math.max(0, det.y); if (box.x < minX) minX = Math.max(0, box.x);
if (det.x + det.width > maxX) if (box.y < minY) minY = Math.max(0, box.y);
maxX = Math.min(metadata.width, det.x + det.width); if (box.x + box.width > maxX)
if (det.y + det.height > maxY) maxX = Math.min(metadata.width, box.x + box.width);
maxY = Math.min(metadata.height, det.y + det.height); if (box.y + box.height > maxY)
maxY = Math.min(metadata.height, box.y + box.height);
} }
const centerX = Math.floor(minX + (maxX - minX) / 2); const centerX = Math.floor(minX + (maxX - minX) / 2);
@@ -213,32 +166,39 @@ export async function processImageWithSmartCrop(
let cropWidth = metadata.width; let cropWidth = metadata.width;
let cropHeight = metadata.height; let cropHeight = metadata.height;
// Determine the maximal crop window that maintains aspect ratio
if (currentRatio > targetRatio) { if (currentRatio > targetRatio) {
cropWidth = Math.floor(metadata.height * targetRatio); cropWidth = Math.floor(metadata.height * targetRatio);
} else { } else {
cropHeight = Math.floor(metadata.width / targetRatio); cropHeight = Math.floor(metadata.width / targetRatio);
} }
// Center the crop window over the center of the faces
let cropX = Math.floor(centerX - cropWidth / 2); let cropX = Math.floor(centerX - cropWidth / 2);
let cropY = Math.floor(centerY - cropHeight / 2); let cropY = Math.floor(centerY - cropHeight / 2);
// Keep crop window inside image bounds
if (cropX < 0) cropX = 0; if (cropX < 0) cropX = 0;
if (cropY < 0) cropY = 0; if (cropY < 0) cropY = 0;
if (cropX + cropWidth > metadata.width) cropX = metadata.width - cropWidth; if (cropX + cropWidth > metadata.width) cropX = metadata.width - cropWidth;
if (cropY + cropHeight > metadata.height) if (cropY + cropHeight > metadata.height)
cropY = metadata.height - cropHeight; cropY = metadata.height - cropHeight;
// Pre-crop the image to isolate the faces before resizing
sharpImage.extract({ sharpImage.extract({
left: cropX, left: cropX,
top: cropY, top: cropY,
width: cropWidth, width: cropWidth,
height: cropHeight, height: cropHeight,
}); });
// As we manually calculated the exact focal box, we can now just center it
cropPosition = "center";
} }
let finalImage = sharpImage.resize(options.width, options.height, { let finalImage = sharpImage.resize(options.width, options.height, {
fit: "cover", fit: "cover",
position: detections.length > 0 ? "center" : "attention", position: cropPosition,
}); });
const format = options.format || "webp"; const format = options.format || "webp";

View File

@@ -0,0 +1,19 @@
import { defineConfig } from "tsup";
export default defineConfig({
entry: ["src/index.ts"],
format: ["esm"],
dts: true,
clean: true,
// Bundle face-api and tensorflow inline (they're pure JS).
// Keep sharp and canvas external (they have native C++ bindings).
noExternal: [
"@vladmandic/face-api",
"@tensorflow/tfjs",
"@tensorflow/tfjs-backend-wasm"
],
external: [
"sharp",
"canvas"
],
});

View File

@@ -176,6 +176,7 @@ Return JSON: { "facts": [ { "statement": "...", "source": "Organization Name Onl
*/ */
async fetchRealSocialPosts( async fetchRealSocialPosts(
topic: string, topic: string,
customSources?: string[],
retries = 1, retries = 1,
): Promise<SocialPost[]> { ): Promise<SocialPost[]> {
console.log( console.log(
@@ -220,7 +221,7 @@ Return a JSON object with a single string field "query". Example: {"query": "cor
if (!videos || videos.length === 0) { if (!videos || videos.length === 0) {
console.warn(`⚠️ [Serper] No videos found for query: "${queryStr}"`); console.warn(`⚠️ [Serper] No videos found for query: "${queryStr}"`);
if (retries > 0) return this.fetchRealSocialPosts(topic, retries - 1); if (retries > 0) return this.fetchRealSocialPosts(topic, customSources, retries - 1);
return []; return [];
} }
@@ -237,11 +238,16 @@ Return a JSON object with a single string field "query". Example: {"query": "cor
if (ytVideos.length === 0) { if (ytVideos.length === 0) {
console.warn(`⚠️ [Serper] No YouTube videos in search results.`); console.warn(`⚠️ [Serper] No YouTube videos in search results.`);
if (retries > 0) return this.fetchRealSocialPosts(topic, retries - 1); if (retries > 0) return this.fetchRealSocialPosts(topic, customSources, retries - 1);
return []; return [];
} }
// Step 3: Ask the LLM to evaluate the relevance of the found videos // Step 3: Ask the LLM to evaluate the relevance of the found videos
const sourceExamples = customSources && customSources.length > 0
? `Specifically prioritize content from: ${customSources.join(", ")}.`
: `(e.g., Google Developers, Vercel, Theo - t3.gg, Fireship, Syntax, ByteByteGo, IBM Technology, McKinsey, Gartner, Deloitte).`;
const evalPrompt = `You are a strict technical evaluator. You must select the MOST RELEVANT educational tech video from the list below based on this core article context: "${topic.slice(0, 800)}..." const evalPrompt = `You are a strict technical evaluator. You must select the MOST RELEVANT educational tech video from the list below based on this core article context: "${topic.slice(0, 800)}..."
Videos: Videos:
@@ -249,7 +255,7 @@ ${ytVideos.map((v, i) => `[ID: ${i}] Title: "${v.title}" | Channel: "${v.channel
RULES: RULES:
1. The video MUST be highly relevant to the EXACT technical topic of the context. 1. The video MUST be highly relevant to the EXACT technical topic of the context.
2. The channel SHOULD be a high-quality tech, development, or professional B2B channel (e.g., Google Developers, Vercel, Theo - t3.gg, Fireship, Syntax, ByteByteGo, IBM Technology, McKinsey, Gartner, Deloitte). AVOID gaming, generic vlogs, clickbait, off-topic podcasts, or unrelated topics. 2. The channel SHOULD be a high-quality tech, development, or professional B2B channel ${sourceExamples} AVOID gaming, generic vlogs, clickbait, off-topic podcasts, or unrelated topics.
3. If none of the videos are strictly relevant to the core technical or business subject (e.g. they are just casually mentioning the word), YOU MUST RETURN -1. Be extremely critical. Do not just pick the "best of the worst". 3. If none of the videos are strictly relevant to the core technical or business subject (e.g. they are just casually mentioning the word), YOU MUST RETURN -1. Be extremely critical. Do not just pick the "best of the worst".
4. If one is highly relevant, return its ID number. 4. If one is highly relevant, return its ID number.
@@ -273,7 +279,7 @@ Return ONLY a JSON object: {"bestVideoId": number}`;
if (bestIdx < 0 || bestIdx >= ytVideos.length) { if (bestIdx < 0 || bestIdx >= ytVideos.length) {
console.warn(`⚠️ [Serper] LLM rejected all videos as irrelevant.`); console.warn(`⚠️ [Serper] LLM rejected all videos as irrelevant.`);
if (retries > 0) return this.fetchRealSocialPosts(topic, retries - 1); if (retries > 0) return this.fetchRealSocialPosts(topic, customSources, retries - 1);
return []; return [];
} }
@@ -342,7 +348,7 @@ CRITICAL: Do NOT provide more than 2 trendsKeywords. Keep it extremely focused.`
try { try {
let parsed = JSON.parse( let parsed = JSON.parse(
response.choices[0].message.content || response.choices[0].message.content ||
'{"trendsKeywords": [], "dcVariables": []}', '{"trendsKeywords": [], "dcVariables": []}',
); );
if (Array.isArray(parsed)) { if (Array.isArray(parsed)) {
parsed = parsed[0] || { trendsKeywords: [], dcVariables: [] }; parsed = parsed[0] || { trendsKeywords: [], dcVariables: [] };

View File

@@ -13,6 +13,8 @@ import {
Footer, Footer,
FoldingMarks, FoldingMarks,
DocumentTitle, DocumentTitle,
COLORS,
FONT_SIZES,
} from "./pdf/SharedUI.js"; } from "./pdf/SharedUI.js";
import { SimpleLayout } from "./pdf/SimpleLayout.js"; import { SimpleLayout } from "./pdf/SimpleLayout.js";
@@ -29,23 +31,23 @@ const localStyles = PDFStyleSheet.create({
marginBottom: 6, marginBottom: 6,
}, },
monoNumber: { monoNumber: {
fontSize: 7, fontSize: FONT_SIZES.TINY,
fontWeight: "bold", fontWeight: "bold",
color: "#94a3b8", color: COLORS.TEXT_LIGHT,
letterSpacing: 2, letterSpacing: 2,
width: 25, width: 25,
}, },
sectionTitle: { sectionTitle: {
fontSize: 9, fontSize: FONT_SIZES.LABEL,
fontWeight: "bold", fontWeight: "bold",
color: "#000000", color: COLORS.CHARCOAL,
textTransform: "uppercase", textTransform: "uppercase",
letterSpacing: 0.5, letterSpacing: 0.5,
}, },
officialText: { officialText: {
fontSize: 8, fontSize: FONT_SIZES.BODY,
lineHeight: 1.5, lineHeight: 1.5,
color: "#334155", color: COLORS.TEXT_MAIN,
textAlign: "justify", textAlign: "justify",
paddingLeft: 25, paddingLeft: 25,
}, },
@@ -100,7 +102,7 @@ export const AgbsPDF = ({
}; };
const content = ( const content = (
<> <PDFView>
<DocumentTitle <DocumentTitle
title="Allgemeine Geschäftsbedingungen" title="Allgemeine Geschäftsbedingungen"
subLines={[`Stand: ${date}`]} subLines={[`Stand: ${date}`]}
@@ -142,7 +144,7 @@ export const AgbsPDF = ({
<AGBSection index="05" title="Abnahme"> <AGBSection index="05" title="Abnahme">
Die Leistung gilt als abgenommen, wenn der Auftraggeber sie produktiv Die Leistung gilt als abgenommen, wenn der Auftraggeber sie produktiv
nutzt oder innerhalb von 7 Tagen nach Bereitstellung keine nutzt oder innerhalb von 30 Tagen nach Bereitstellung keine
wesentlichen Mängel angezeigt werden. Optische Abweichungen, wesentlichen Mängel angezeigt werden. Optische Abweichungen,
Geschmacksfragen oder subjektive Einschätzungen stellen keine Mängel Geschmacksfragen oder subjektive Einschätzungen stellen keine Mängel
dar. dar.
@@ -206,7 +208,7 @@ export const AgbsPDF = ({
bleibt die Wirksamkeit der übrigen Regelungen unberührt. bleibt die Wirksamkeit der übrigen Regelungen unberührt.
</AGBSection> </AGBSection>
</PDFView> </PDFView>
</> </PDFView>
); );
if (mode === "full") { if (mode === "full") {
@@ -214,9 +216,8 @@ export const AgbsPDF = ({
<SimpleLayout <SimpleLayout
companyData={companyData} companyData={companyData}
bankData={bankData} bankData={bankData}
headerIcon={headerIcon}
footerLogo={footerLogo} footerLogo={footerLogo}
icon={headerIcon}
pageNumber="10"
showPageNumber={false} showPageNumber={false}
> >
{content} {content}
@@ -232,7 +233,7 @@ export const AgbsPDF = ({
<Footer <Footer
logo={footerLogo} logo={footerLogo}
companyData={companyData} companyData={companyData}
bankData={bankData} _bankData={bankData}
showDetails={false} showDetails={false}
showPageNumber={false} showPageNumber={false}
/> />

View File

@@ -46,7 +46,7 @@ export const CombinedQuotePDF = ({
const layoutProps = { const layoutProps = {
date, date,
icon: estimationProps.headerIcon, headerIcon: estimationProps.headerIcon,
footerLogo: estimationProps.footerLogo, footerLogo: estimationProps.footerLogo,
companyData, companyData,
bankData, bankData,
@@ -71,7 +71,7 @@ export const CombinedQuotePDF = ({
footerLogo={estimationProps.footerLogo} footerLogo={estimationProps.footerLogo}
/> />
)} )}
<SimpleLayout {...layoutProps} pageNumber="END" showPageNumber={false}> <SimpleLayout {...layoutProps} showPageNumber={false}>
<ClosingModule /> <ClosingModule />
</SimpleLayout> </SimpleLayout>
</PDFDocument> </PDFDocument>

View File

@@ -50,7 +50,7 @@ export const EstimationPDF = ({
const commonProps = { const commonProps = {
state, state,
date, date,
icon: headerIcon, headerIcon,
footerLogo, footerLogo,
companyData, companyData,
}; };
@@ -64,17 +64,17 @@ export const EstimationPDF = ({
<FrontPageModule state={state} headerIcon={headerIcon} date={date} /> <FrontPageModule state={state} headerIcon={headerIcon} date={date} />
</PDFPage> </PDFPage>
<SimpleLayout {...commonProps} pageNumber={getPageNum()}> <SimpleLayout {...commonProps}>
<BriefingModule state={state} /> <BriefingModule state={state} />
</SimpleLayout> </SimpleLayout>
{state.sitemap && state.sitemap.length > 0 && ( {state.sitemap && state.sitemap.length > 0 && (
<SimpleLayout {...commonProps} pageNumber={getPageNum()}> <SimpleLayout {...commonProps}>
<SitemapModule state={state} /> <SitemapModule state={state} />
</SimpleLayout> </SimpleLayout>
)} )}
<SimpleLayout {...commonProps} pageNumber={getPageNum()}> <SimpleLayout {...commonProps}>
<EstimationModule <EstimationModule
state={state} state={state}
positions={positions} positions={positions}
@@ -83,11 +83,11 @@ export const EstimationPDF = ({
/> />
</SimpleLayout> </SimpleLayout>
<SimpleLayout {...commonProps} pageNumber={getPageNum()}> <SimpleLayout {...commonProps}>
<TransparenzModule pricing={pricing} /> <TransparenzModule pricing={pricing} />
</SimpleLayout> </SimpleLayout>
<SimpleLayout {...commonProps} pageNumber={getPageNum()}> <SimpleLayout {...commonProps}>
<ClosingModule /> <ClosingModule />
</SimpleLayout> </SimpleLayout>
</PDFDocument> </PDFDocument>

View File

@@ -8,58 +8,48 @@ const simpleStyles = StyleSheet.create({
industrialPage: { industrialPage: {
padding: 30, padding: 30,
paddingTop: 20, paddingTop: 20,
backgroundColor: '#ffffff', flexDirection: 'column',
backgroundColor: '#FFFFFF',
fontFamily: 'Outfit',
}, },
industrialNumber: { contentView: {
fontSize: 60, flex: 1,
fontWeight: 'bold', marginTop: 20,
color: '#f1f5f9',
position: 'absolute',
top: -10,
right: 0,
zIndex: -1,
},
industrialSection: {
marginTop: 16,
paddingTop: 12,
flexDirection: 'row',
position: 'relative',
}, },
}); });
interface SimpleLayoutProps { interface SimpleLayoutProps {
children: React.ReactNode; headerIcon?: string;
pageNumber?: string;
icon?: string;
footerLogo?: string; footerLogo?: string;
companyData: any; companyData: any;
bankData?: any; bankData?: any;
showDetails?: boolean;
showPageNumber?: boolean; showPageNumber?: boolean;
children: React.ReactNode;
} }
export const SimpleLayout = ({ export const SimpleLayout: React.FC<SimpleLayoutProps> = ({
children, headerIcon,
pageNumber,
icon,
footerLogo, footerLogo,
companyData, companyData,
bankData, bankData,
showPageNumber = true showDetails = false,
}: SimpleLayoutProps) => { showPageNumber = true,
children,
}) => {
return ( return (
<PDFPage size="A4" style={[pdfStyles.page, simpleStyles.industrialPage]}> <PDFPage size="A4" style={simpleStyles.industrialPage}>
<Header icon={icon} showAddress={false} /> <Header icon={headerIcon} sender={companyData.name} showAddress={false} />
{pageNumber && <PDFText style={simpleStyles.industrialNumber}>{pageNumber}</PDFText>}
<PDFView style={simpleStyles.industrialSection}> <PDFView style={simpleStyles.contentView}>
<PDFView style={{ width: '100%' }}> {children}
{children}
</PDFView>
</PDFView> </PDFView>
<Footer <Footer
logo={footerLogo} logo={footerLogo}
companyData={companyData} companyData={companyData}
bankData={bankData} _bankData={bankData}
showDetails={false} showDetails={showDetails}
showPageNumber={showPageNumber} showPageNumber={showPageNumber}
/> />
</PDFPage> </PDFPage>

View File

@@ -0,0 +1,53 @@
import { renderToFile, Document as PDFDocument, Font } from "@react-pdf/renderer";
import { createElement } from "react";
import { AgbsPDF } from "./components/AgbsPDF.js";
import path from "path";
import fs from "fs";
import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Standard Font Registration
Font.register({
family: 'Outfit',
fonts: [
{ src: 'Helvetica' },
{ src: 'Helvetica-Bold', fontWeight: 'bold' },
],
});
Font.register({
family: 'Helvetica',
fonts: [
{ src: 'Helvetica' },
{ src: 'Helvetica-Bold', fontWeight: 'bold' },
],
});
async function generate() {
const outDir = path.join(__dirname, "../../../out");
if (!fs.existsSync(outDir)) {
fs.mkdirSync(outDir, { recursive: true });
}
const outputPath = path.resolve(outDir, "AGB_Mintel.pdf");
console.log("Generating High-Fidelity AGB PDF...");
const headerIcon = "/Users/marcmintel/Projects/mintel.me/apps/web/src/assets/logo/Icon-White-Transparent.png";
const footerLogo = "/Users/marcmintel/Projects/mintel.me/apps/web/src/assets/logo/Logo-Black-Transparent.png";
// WRAP IN DOCUMENT - MANDATORY FOR standalone rendering
const document = createElement(PDFDocument, {
title: "Allgemeine Geschäftsbedingungen - Marc Mintel",
author: "Marc Mintel",
},
createElement(AgbsPDF, { mode: "full", headerIcon, footerLogo })
);
await renderToFile(document, outputPath);
console.log(`Generated: ${outputPath}`);
}
generate().catch(console.error);

View File

@@ -56,8 +56,8 @@ export class ThumbnailGenerator {
} }
} }
// Default to the requested nano-banana-pro model unless explicitly provided // Default to the requested flux-1.1-pro model unless explicitly provided
const model = options?.model || "google/nano-banana-pro"; const model = options?.model || "black-forest-labs/flux-1.1-pro";
const output = await this.replicate.run(model as `${string}/${string}`, { const output = await this.replicate.run(model as `${string}/${string}`, {
input: inputPayload, input: inputPayload,

14
plan_free.hbs Normal file
View File

@@ -0,0 +1,14 @@
<div class="membership-card free">
<div class="membership-card-content">
<h2 class="membership-card-title">{{t "Free"}}</h2>
<h3 class="membership-card-price"><sup>$</sup>0</h3>
<div class="membership-card-options">
<ul>
<li>Full access to posts for subscribers</li>
<li>Weekly email newsletter</li>
<li>No advertising</li>
</ul>
</div>
</div>
<a href="{{@site.url}}/signup/" class="global-button">{{t "Subscribe now"}}</a>
</div>

16
plan_monthly.hbs Normal file
View File

@@ -0,0 +1,16 @@
<div class="membership-card monthly">
<div class="membership-card-content">
<h2 class="membership-card-title">{{t "Monthly"}}</h2>
<h3 class="membership-card-price">{{price monthly_price currency=currency}}</h3>
<div class="membership-card-options">
<ul>
<li>Full access to all premium posts</li>
<li>Weekly email newsletter</li>
<li>Support independent publishing</li>
<li>Simple, secure card payment</li>
<li>No advertising</li>
</ul>
</div>
</div>
<a href="#" class="global-button" data-members-plan="Monthly">{{t "Subscribe now"}}</a>
</div>

17
plan_yearly.hbs Normal file
View File

@@ -0,0 +1,17 @@
<div class="membership-card yearly">
<div class="membership-card-content">
<h2 class="membership-card-title">{{t "Yearly"}}</h2>
<h3 class="membership-card-price">{{price yearly_price currency=currency}}</h3>
<div class="membership-card-options">
<ul>
<li>Full access to all premium posts</li>
<li>Weekly email newsletter</li>
<li>Support independent publishing</li>
<li>Simple, secure card payment</li>
<li>One easy payment instead of 12!</li>
<li>No advertising</li>
</ul>
</div>
</div>
<a href="#" class="global-button" data-members-plan="Yearly">{{t "Subscribe now"}}</a>
</div>

403
pnpm-lock.yaml generated
View File

@@ -81,7 +81,7 @@ importers:
version: 9.1.7 version: 9.1.7
jsdom: jsdom:
specifier: ^27.4.0 specifier: ^27.4.0
version: 27.4.0 version: 27.4.0(canvas@3.2.1)
lint-staged: lint-staged:
specifier: ^16.2.7 specifier: ^16.2.7
version: 16.2.7 version: 16.2.7
@@ -99,7 +99,7 @@ importers:
version: 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) version: 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
vitest: vitest:
specifier: ^4.0.18 specifier: ^4.0.18
version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@20.19.33)(@vitest/ui@4.0.18)(happy-dom@20.5.3)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@20.19.33)(@vitest/ui@4.0.18)(happy-dom@20.5.3)(jiti@2.6.1)(jsdom@27.4.0(canvas@3.2.1))(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)
apps/image-service: apps/image-service:
dependencies: dependencies:
@@ -260,7 +260,7 @@ importers:
version: 1.2.0 version: 1.2.0
crawlee: crawlee:
specifier: ^3.7.0 specifier: ^3.7.0
version: 3.16.0(@types/node@22.19.10)(playwright@1.58.2) version: 3.16.0(@types/node@22.19.10)(canvas@3.2.1)(playwright@1.58.2)
playwright: playwright:
specifier: ^1.40.0 specifier: ^1.40.0
version: 1.58.2 version: 1.58.2
@@ -457,6 +457,15 @@ importers:
packages/image-processor: packages/image-processor:
dependencies: dependencies:
'@tensorflow/tfjs':
specifier: ^4.22.0
version: 4.22.0(seedrandom@3.0.5)
'@vladmandic/face-api':
specifier: ^1.7.15
version: 1.7.15
canvas:
specifier: ^3.2.1
version: 3.2.1
sharp: sharp:
specifier: ^0.33.2 specifier: ^0.33.2
version: 0.33.5 version: 0.33.5
@@ -555,7 +564,7 @@ importers:
version: 5.9.3 version: 5.9.3
vitest: vitest:
specifier: ^3.0.4 specifier: ^3.0.4
version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.10)(@vitest/ui@4.0.18)(happy-dom@20.5.3)(jsdom@27.4.0)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0) version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.10)(@vitest/ui@4.0.18)(happy-dom@20.5.3)(jsdom@27.4.0(canvas@3.2.1))(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)
packages/meme-generator: packages/meme-generator:
dependencies: dependencies:
@@ -736,7 +745,7 @@ importers:
version: 5.9.3 version: 5.9.3
vitest: vitest:
specifier: ^2.0.0 specifier: ^2.0.0
version: 2.1.9(@types/node@22.19.10)(@vitest/ui@4.0.18)(happy-dom@20.5.3)(jsdom@27.4.0)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0) version: 2.1.9(@types/node@22.19.10)(@vitest/ui@4.0.18)(happy-dom@20.5.3)(jsdom@27.4.0(canvas@3.2.1))(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)
packages/pdf-library: packages/pdf-library:
dependencies: dependencies:
@@ -3416,6 +3425,42 @@ packages:
peerDependencies: peerDependencies:
tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1' tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1'
'@tensorflow/tfjs-backend-cpu@4.22.0':
resolution: {integrity: sha512-1u0FmuLGuRAi8D2c3cocHTASGXOmHc/4OvoVDENJayjYkS119fcTcQf4iHrtLthWyDIPy3JiPhRrZQC9EwnhLw==}
engines: {yarn: '>= 1.3.2'}
peerDependencies:
'@tensorflow/tfjs-core': 4.22.0
'@tensorflow/tfjs-backend-webgl@4.22.0':
resolution: {integrity: sha512-H535XtZWnWgNwSzv538czjVlbJebDl5QTMOth4RXr2p/kJ1qSIXE0vZvEtO+5EC9b00SvhplECny2yDewQb/Yg==}
engines: {yarn: '>= 1.3.2'}
peerDependencies:
'@tensorflow/tfjs-core': 4.22.0
'@tensorflow/tfjs-converter@4.22.0':
resolution: {integrity: sha512-PT43MGlnzIo+YfbsjM79Lxk9lOq6uUwZuCc8rrp0hfpLjF6Jv8jS84u2jFb+WpUeuF4K33ZDNx8CjiYrGQ2trQ==}
peerDependencies:
'@tensorflow/tfjs-core': 4.22.0
'@tensorflow/tfjs-core@4.22.0':
resolution: {integrity: sha512-LEkOyzbknKFoWUwfkr59vSB68DMJ4cjwwHgicXN0DUi3a0Vh1Er3JQqCI1Hl86GGZQvY8ezVrtDIvqR1ZFW55A==}
engines: {yarn: '>= 1.3.2'}
'@tensorflow/tfjs-data@4.22.0':
resolution: {integrity: sha512-dYmF3LihQIGvtgJrt382hSRH4S0QuAp2w1hXJI2+kOaEqo5HnUPG0k5KA6va+S1yUhx7UBToUKCBHeLHFQRV4w==}
peerDependencies:
'@tensorflow/tfjs-core': 4.22.0
seedrandom: ^3.0.5
'@tensorflow/tfjs-layers@4.22.0':
resolution: {integrity: sha512-lybPj4ZNj9iIAPUj7a8ZW1hg8KQGfqWLlCZDi9eM/oNKCCAgchiyzx8OrYoWmRrB+AM6VNEeIT+2gZKg5ReihA==}
peerDependencies:
'@tensorflow/tfjs-core': 4.22.0
'@tensorflow/tfjs@4.22.0':
resolution: {integrity: sha512-0TrIrXs6/b7FLhLVNmfh8Sah6JgjBPH4mZ8JGb7NU6WW+cx00qK5BcAZxw7NCzxj6N8MRAIfHq+oNbPUNG5VAg==}
hasBin: true
'@testing-library/dom@10.4.1': '@testing-library/dom@10.4.1':
resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==}
engines: {node: '>=18'} engines: {node: '>=18'}
@@ -3529,6 +3574,9 @@ packages:
'@types/jsonfile@6.1.4': '@types/jsonfile@6.1.4':
resolution: {integrity: sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==} resolution: {integrity: sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==}
'@types/long@4.0.2':
resolution: {integrity: sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==}
'@types/ms@2.1.0': '@types/ms@2.1.0':
resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
@@ -3550,6 +3598,12 @@ packages:
'@types/node@22.19.10': '@types/node@22.19.10':
resolution: {integrity: sha512-tF5VOugLS/EuDlTBijk0MqABfP8UxgYazTLo3uIn3b4yJgg26QRbVYJYsDtHrjdDUIRfP70+VfhTTc+CE1yskw==} resolution: {integrity: sha512-tF5VOugLS/EuDlTBijk0MqABfP8UxgYazTLo3uIn3b4yJgg26QRbVYJYsDtHrjdDUIRfP70+VfhTTc+CE1yskw==}
'@types/offscreencanvas@2019.3.0':
resolution: {integrity: sha512-esIJx9bQg+QYF0ra8GnvfianIY8qWB0GBx54PK5Eps6m+xTj86KLavHv6qDhzKcu5UUOgNfJ2pWaIIV7TRUd9Q==}
'@types/offscreencanvas@2019.7.3':
resolution: {integrity: sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==}
'@types/parse-json@4.0.2': '@types/parse-json@4.0.2':
resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==}
@@ -3582,6 +3636,9 @@ packages:
'@types/sax@1.2.7': '@types/sax@1.2.7':
resolution: {integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==} resolution: {integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==}
'@types/seedrandom@2.4.34':
resolution: {integrity: sha512-ytDiArvrn/3Xk6/vtylys5tlY6eo7Ane0hvcx++TKo6RxQXuVfW0AF/oeWqAj9dN29SyhtawuXstgmPlwNcv/A==}
'@types/send@1.2.1': '@types/send@1.2.1':
resolution: {integrity: sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==} resolution: {integrity: sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==}
@@ -3884,6 +3941,10 @@ packages:
resolution: {integrity: sha512-Xfe6rpCTxSxfbswi/W/Pz7zp1WWSNn4A0eW4mLkQUewCrXXtMj31lCg+iQyTkh/CkusZSq9eDflu7tjEDXUY6g==} resolution: {integrity: sha512-Xfe6rpCTxSxfbswi/W/Pz7zp1WWSNn4A0eW4mLkQUewCrXXtMj31lCg+iQyTkh/CkusZSq9eDflu7tjEDXUY6g==}
engines: {node: '>=v14.0.0', npm: '>=7.0.0'} engines: {node: '>=v14.0.0', npm: '>=7.0.0'}
'@vladmandic/face-api@1.7.15':
resolution: {integrity: sha512-WDMmK3CfNLo8jylWqMoQgf4nIst3M0fzx1dnac96wv/dvMTN4DxC/Pq1DGtduDk1lktCamQ3MIDXFnvrdHTXDw==}
engines: {node: '>=14.0.0'}
'@vue/compiler-core@3.4.21': '@vue/compiler-core@3.4.21':
resolution: {integrity: sha512-MjXawxZf2SbZszLPYxaFCjxfibYrzr3eYbKxwpLR9EQN+oaziSu3qKVbwBERj1IFIB8OLUewxB5m/BFzi613og==} resolution: {integrity: sha512-MjXawxZf2SbZszLPYxaFCjxfibYrzr3eYbKxwpLR9EQN+oaziSu3qKVbwBERj1IFIB8OLUewxB5m/BFzi613og==}
@@ -3990,6 +4051,9 @@ packages:
'@webassemblyjs/wast-printer@1.14.1': '@webassemblyjs/wast-printer@1.14.1':
resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==}
'@webgpu/types@0.1.38':
resolution: {integrity: sha512-7LrhVKz2PRh+DD7+S+PVaFd5HxaWQvoMqBbsV9fNJO1pjUs1P8bM2vQVNfk+3URTqbuTI7gkXi0rfsN0IadoBA==}
'@xtuc/ieee754@1.2.0': '@xtuc/ieee754@1.2.0':
resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==}
@@ -4342,6 +4406,10 @@ packages:
caniuse-lite@1.0.30001769: caniuse-lite@1.0.30001769:
resolution: {integrity: sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==} resolution: {integrity: sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==}
canvas@3.2.1:
resolution: {integrity: sha512-ej1sPFR5+0YWtaVp6S1N1FVz69TQCqmrkGeRvQxZeAB1nAIcjNTHVwrZtYtWFFBmQsF40/uDLehsW5KuYC99mg==}
engines: {node: ^18.12.0 || >= 20.9.0}
chai@5.3.3: chai@5.3.3:
resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==}
engines: {node: '>=18'} engines: {node: '>=18'}
@@ -4395,6 +4463,9 @@ packages:
resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
engines: {node: '>= 14.16.0'} engines: {node: '>= 14.16.0'}
chownr@1.1.4:
resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
chrome-trace-event@1.0.4: chrome-trace-event@1.0.4:
resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==}
engines: {node: '>=6.0'} engines: {node: '>=6.0'}
@@ -4437,6 +4508,9 @@ packages:
client-only@0.0.1: client-only@0.0.1:
resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
cliui@7.0.4:
resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==}
cliui@8.0.1: cliui@8.0.1:
resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
engines: {node: '>=12'} engines: {node: '>=12'}
@@ -4543,6 +4617,9 @@ packages:
resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==}
engines: {node: '>= 0.6'} engines: {node: '>= 0.6'}
core-js@3.29.1:
resolution: {integrity: sha512-+jwgnhg6cQxKYIIjGtAHq2nwUOolo9eoFZ4sHfUH09BLXBgxnH4gA0zEd+t+BO2cNB8idaBtZFcFTRjQJRJmAw==}
cosmiconfig-typescript-loader@6.2.0: cosmiconfig-typescript-loader@6.2.0:
resolution: {integrity: sha512-GEN39v7TgdxgIoNcdkRE3uiAzQt3UXLyHbRHD6YoL048XAeOomyxaP+Hh/+2C6C2wYjxJ2onhJcsQp+L4YEkVQ==} resolution: {integrity: sha512-GEN39v7TgdxgIoNcdkRE3uiAzQt3UXLyHbRHD6YoL048XAeOomyxaP+Hh/+2C6C2wYjxJ2onhJcsQp+L4YEkVQ==}
engines: {node: '>=v18'} engines: {node: '>=v18'}
@@ -4735,10 +4812,18 @@ packages:
resolution: {integrity: sha512-oj7KWToJuuxlPr7VV0vabvxEIiqNMo+q0NueIiL3XhtwC6FVOX7Hr1c0C4eD0bmf7Zr+S/dSf2xvkH3Ad6sU3Q==} resolution: {integrity: sha512-oj7KWToJuuxlPr7VV0vabvxEIiqNMo+q0NueIiL3XhtwC6FVOX7Hr1c0C4eD0bmf7Zr+S/dSf2xvkH3Ad6sU3Q==}
engines: {node: '>=20'} engines: {node: '>=20'}
decompress-response@6.0.0:
resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==}
engines: {node: '>=10'}
deep-eql@5.0.2: deep-eql@5.0.2:
resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
engines: {node: '>=6'} engines: {node: '>=6'}
deep-extend@0.6.0:
resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
engines: {node: '>=4.0.0'}
deep-is@0.1.4: deep-is@0.1.4:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
@@ -5142,6 +5227,10 @@ packages:
resolution: {integrity: sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==} resolution: {integrity: sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==}
engines: {node: ^14.18.0 || ^16.14.0 || >=18.0.0} engines: {node: ^14.18.0 || ^16.14.0 || >=18.0.0}
expand-template@2.0.3:
resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==}
engines: {node: '>=6'}
expect-type@1.3.0: expect-type@1.3.0:
resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==}
engines: {node: '>=12.0.0'} engines: {node: '>=12.0.0'}
@@ -5345,6 +5434,9 @@ packages:
from@0.1.7: from@0.1.7:
resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==} resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==}
fs-constants@1.0.0:
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
fs-extra@10.1.0: fs-extra@10.1.0:
resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==}
engines: {node: '>=12'} engines: {node: '>=12'}
@@ -5442,6 +5534,9 @@ packages:
engines: {node: '>=16'} engines: {node: '>=16'}
hasBin: true hasBin: true
github-from-package@0.0.0:
resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==}
glob-parent@5.1.2: glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'} engines: {node: '>= 6'}
@@ -5697,6 +5792,9 @@ packages:
inherits@2.0.4: inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
ini@1.3.8:
resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
ini@4.1.1: ini@4.1.1:
resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==} resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
@@ -6249,6 +6347,9 @@ packages:
resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==}
engines: {node: '>=18'} engines: {node: '>=18'}
long@4.0.0:
resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==}
loose-envify@1.4.0: loose-envify@1.4.0:
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
hasBin: true hasBin: true
@@ -6360,6 +6461,10 @@ packages:
resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==}
engines: {node: '>=18'} engines: {node: '>=18'}
mimic-response@3.1.0:
resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
engines: {node: '>=10'}
mimic-response@4.0.0: mimic-response@4.0.0:
resolution: {integrity: sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==} resolution: {integrity: sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@@ -6386,6 +6491,9 @@ packages:
resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
engines: {node: '>=16 || 14 >=14.17'} engines: {node: '>=16 || 14 >=14.17'}
mkdirp-classic@0.5.3:
resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
ml-array-max@1.2.4: ml-array-max@1.2.4:
resolution: {integrity: sha512-BlEeg80jI0tW6WaPyGxf5Sa4sqvcyY6lbSn5Vcv44lp1I2GR6AWojfUvLnGTNsIXrZ8uqWmo8VcG1WpkI2ONMQ==} resolution: {integrity: sha512-BlEeg80jI0tW6WaPyGxf5Sa4sqvcyY6lbSn5Vcv44lp1I2GR6AWojfUvLnGTNsIXrZ8uqWmo8VcG1WpkI2ONMQ==}
@@ -6451,6 +6559,9 @@ packages:
engines: {node: ^18 || >=20} engines: {node: ^18 || >=20}
hasBin: true hasBin: true
napi-build-utils@2.0.0:
resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==}
napi-postinstall@0.3.4: napi-postinstall@0.3.4:
resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==}
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
@@ -6500,6 +6611,10 @@ packages:
sass: sass:
optional: true optional: true
node-abi@3.87.0:
resolution: {integrity: sha512-+CGM1L1CgmtheLcBuleyYOn7NWPVu0s0EJH2C4puxgEZb9h8QpR9G2dBfZJOAUhi7VQxuBPMd0hiISWcTyiYyQ==}
engines: {node: '>=10'}
node-addon-api@7.1.1: node-addon-api@7.1.1:
resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==}
@@ -6508,6 +6623,15 @@ packages:
engines: {node: '>=10.5.0'} engines: {node: '>=10.5.0'}
deprecated: Use your platform's native DOMException instead deprecated: Use your platform's native DOMException instead
node-fetch@2.6.13:
resolution: {integrity: sha512-StxNAxh15zr77QvvkmveSQ8uCQ4+v5FkvNTj0OESmiHu+VRi/gXArXtkWMElOsOUNLtUEvI4yS+rdtOHZTwlQA==}
engines: {node: 4.x || >=6.0.0}
peerDependencies:
encoding: ^0.1.0
peerDependenciesMeta:
encoding:
optional: true
node-fetch@2.7.0: node-fetch@2.7.0:
resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
engines: {node: 4.x || >=6.0.0} engines: {node: 4.x || >=6.0.0}
@@ -7130,6 +7254,12 @@ packages:
resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
prebuild-install@7.1.3:
resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==}
engines: {node: '>=10'}
deprecated: No longer maintained. Please contact the author of the relevant native addon; alternatives are available.
hasBin: true
prelude-ls@1.2.1: prelude-ls@1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'} engines: {node: '>= 0.8.0'}
@@ -7226,6 +7356,10 @@ packages:
randombytes@2.1.0: randombytes@2.1.0:
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
rc@1.2.8:
resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
hasBin: true
react-dom@19.2.4: react-dom@19.2.4:
resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==}
peerDependencies: peerDependencies:
@@ -7287,6 +7421,9 @@ packages:
resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
regenerator-runtime@0.13.11:
resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==}
regexp.prototype.flags@1.5.4: regexp.prototype.flags@1.5.4:
resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
@@ -7466,6 +7603,9 @@ packages:
secure-json-parse@4.1.0: secure-json-parse@4.1.0:
resolution: {integrity: sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==} resolution: {integrity: sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==}
seedrandom@3.0.5:
resolution: {integrity: sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==}
selderee@0.11.0: selderee@0.11.0:
resolution: {integrity: sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==} resolution: {integrity: sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==}
@@ -7538,6 +7678,12 @@ packages:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'} engines: {node: '>=14'}
simple-concat@1.0.1:
resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
simple-get@4.0.1:
resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==}
simple-swizzle@0.2.4: simple-swizzle@0.2.4:
resolution: {integrity: sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==} resolution: {integrity: sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==}
@@ -7718,6 +7864,10 @@ packages:
resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==}
engines: {node: '>=8'} engines: {node: '>=8'}
strip-json-comments@2.0.1:
resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
engines: {node: '>=0.10.0'}
strip-json-comments@3.1.1: strip-json-comments@3.1.1:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'} engines: {node: '>=8'}
@@ -7796,6 +7946,13 @@ packages:
resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==}
engines: {node: '>=6'} engines: {node: '>=6'}
tar-fs@2.1.4:
resolution: {integrity: sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==}
tar-stream@2.2.0:
resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
engines: {node: '>=6'}
tarn@3.0.2: tarn@3.0.2:
resolution: {integrity: sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ==} resolution: {integrity: sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ==}
engines: {node: '>=8.0.0'} engines: {node: '>=8.0.0'}
@@ -7989,6 +8146,9 @@ packages:
engines: {node: '>=18.0.0'} engines: {node: '>=18.0.0'}
hasBin: true hasBin: true
tunnel-agent@0.6.0:
resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
type-check@0.4.0: type-check@0.4.0:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'} engines: {node: '>= 0.8.0'}
@@ -8501,10 +8661,18 @@ packages:
yargonaut@1.1.4: yargonaut@1.1.4:
resolution: {integrity: sha512-rHgFmbgXAAzl+1nngqOcwEljqHGG9uUZoPjsdZEs1w5JW9RXYzrSvH/u70C1JE5qFi0qjsdhnUX/dJRpWqitSA==} resolution: {integrity: sha512-rHgFmbgXAAzl+1nngqOcwEljqHGG9uUZoPjsdZEs1w5JW9RXYzrSvH/u70C1JE5qFi0qjsdhnUX/dJRpWqitSA==}
yargs-parser@20.2.9:
resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==}
engines: {node: '>=10'}
yargs-parser@21.1.1: yargs-parser@21.1.1:
resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
engines: {node: '>=12'} engines: {node: '>=12'}
yargs@16.2.0:
resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==}
engines: {node: '>=10'}
yargs@17.7.2: yargs@17.7.2:
resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
engines: {node: '>=12'} engines: {node: '>=12'}
@@ -9094,7 +9262,7 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@crawlee/jsdom@3.16.0': '@crawlee/jsdom@3.16.0(canvas@3.2.1)':
dependencies: dependencies:
'@apify/timeout': 0.3.2 '@apify/timeout': 0.3.2
'@apify/utilities': 2.25.4 '@apify/utilities': 2.25.4
@@ -9103,7 +9271,7 @@ snapshots:
'@crawlee/utils': 3.16.0 '@crawlee/utils': 3.16.0
'@types/jsdom': 21.1.7 '@types/jsdom': 21.1.7
cheerio: 1.0.0-rc.12 cheerio: 1.0.0-rc.12
jsdom: 26.1.0 jsdom: 26.1.0(canvas@3.2.1)
ow: 0.28.2 ow: 0.28.2
tslib: 2.8.1 tslib: 2.8.1
transitivePeerDependencies: transitivePeerDependencies:
@@ -9112,13 +9280,13 @@ snapshots:
- supports-color - supports-color
- utf-8-validate - utf-8-validate
'@crawlee/linkedom@3.16.0': '@crawlee/linkedom@3.16.0(canvas@3.2.1)':
dependencies: dependencies:
'@apify/timeout': 0.3.2 '@apify/timeout': 0.3.2
'@apify/utilities': 2.25.4 '@apify/utilities': 2.25.4
'@crawlee/http': 3.16.0 '@crawlee/http': 3.16.0
'@crawlee/types': 3.16.0 '@crawlee/types': 3.16.0
linkedom: 0.18.12 linkedom: 0.18.12(canvas@3.2.1)
ow: 0.28.2 ow: 0.28.2
tslib: 2.8.1 tslib: 2.8.1
transitivePeerDependencies: transitivePeerDependencies:
@@ -11298,6 +11466,67 @@ snapshots:
postcss-selector-parser: 6.0.10 postcss-selector-parser: 6.0.10
tailwindcss: 3.4.19(tsx@4.21.0)(yaml@2.8.2) tailwindcss: 3.4.19(tsx@4.21.0)(yaml@2.8.2)
'@tensorflow/tfjs-backend-cpu@4.22.0(@tensorflow/tfjs-core@4.22.0)':
dependencies:
'@tensorflow/tfjs-core': 4.22.0
'@types/seedrandom': 2.4.34
seedrandom: 3.0.5
'@tensorflow/tfjs-backend-webgl@4.22.0(@tensorflow/tfjs-core@4.22.0)':
dependencies:
'@tensorflow/tfjs-backend-cpu': 4.22.0(@tensorflow/tfjs-core@4.22.0)
'@tensorflow/tfjs-core': 4.22.0
'@types/offscreencanvas': 2019.3.0
'@types/seedrandom': 2.4.34
seedrandom: 3.0.5
'@tensorflow/tfjs-converter@4.22.0(@tensorflow/tfjs-core@4.22.0)':
dependencies:
'@tensorflow/tfjs-core': 4.22.0
'@tensorflow/tfjs-core@4.22.0':
dependencies:
'@types/long': 4.0.2
'@types/offscreencanvas': 2019.7.3
'@types/seedrandom': 2.4.34
'@webgpu/types': 0.1.38
long: 4.0.0
node-fetch: 2.6.13
seedrandom: 3.0.5
transitivePeerDependencies:
- encoding
'@tensorflow/tfjs-data@4.22.0(@tensorflow/tfjs-core@4.22.0)(seedrandom@3.0.5)':
dependencies:
'@tensorflow/tfjs-core': 4.22.0
'@types/node-fetch': 2.6.13
node-fetch: 2.6.13
seedrandom: 3.0.5
string_decoder: 1.3.0
transitivePeerDependencies:
- encoding
'@tensorflow/tfjs-layers@4.22.0(@tensorflow/tfjs-core@4.22.0)':
dependencies:
'@tensorflow/tfjs-core': 4.22.0
'@tensorflow/tfjs@4.22.0(seedrandom@3.0.5)':
dependencies:
'@tensorflow/tfjs-backend-cpu': 4.22.0(@tensorflow/tfjs-core@4.22.0)
'@tensorflow/tfjs-backend-webgl': 4.22.0(@tensorflow/tfjs-core@4.22.0)
'@tensorflow/tfjs-converter': 4.22.0(@tensorflow/tfjs-core@4.22.0)
'@tensorflow/tfjs-core': 4.22.0
'@tensorflow/tfjs-data': 4.22.0(@tensorflow/tfjs-core@4.22.0)(seedrandom@3.0.5)
'@tensorflow/tfjs-layers': 4.22.0(@tensorflow/tfjs-core@4.22.0)
argparse: 1.0.10
chalk: 4.1.2
core-js: 3.29.1
regenerator-runtime: 0.13.11
yargs: 16.2.0
transitivePeerDependencies:
- encoding
- seedrandom
'@testing-library/dom@10.4.1': '@testing-library/dom@10.4.1':
dependencies: dependencies:
'@babel/code-frame': 7.29.0 '@babel/code-frame': 7.29.0
@@ -11448,6 +11677,8 @@ snapshots:
dependencies: dependencies:
'@types/node': 20.19.33 '@types/node': 20.19.33
'@types/long@4.0.2': {}
'@types/ms@2.1.0': '@types/ms@2.1.0':
optional: true optional: true
@@ -11474,6 +11705,10 @@ snapshots:
dependencies: dependencies:
undici-types: 6.21.0 undici-types: 6.21.0
'@types/offscreencanvas@2019.3.0': {}
'@types/offscreencanvas@2019.7.3': {}
'@types/parse-json@4.0.2': {} '@types/parse-json@4.0.2': {}
'@types/pg-pool@2.0.7': '@types/pg-pool@2.0.7':
@@ -11509,6 +11744,8 @@ snapshots:
dependencies: dependencies:
'@types/node': 20.19.33 '@types/node': 20.19.33
'@types/seedrandom@2.4.34': {}
'@types/send@1.2.1': '@types/send@1.2.1':
dependencies: dependencies:
'@types/node': 20.19.33 '@types/node': 20.19.33
@@ -11847,7 +12084,7 @@ snapshots:
sirv: 3.0.2 sirv: 3.0.2
tinyglobby: 0.2.15 tinyglobby: 0.2.15
tinyrainbow: 3.0.3 tinyrainbow: 3.0.3
vitest: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@20.19.33)(@vitest/ui@4.0.18)(happy-dom@20.5.3)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) vitest: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@20.19.33)(@vitest/ui@4.0.18)(happy-dom@20.5.3)(jiti@2.6.1)(jsdom@27.4.0(canvas@3.2.1))(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)
optional: true optional: true
'@vitest/utils@2.1.9': '@vitest/utils@2.1.9':
@@ -11869,6 +12106,8 @@ snapshots:
'@vladfrangu/async_event_emitter@2.4.7': {} '@vladfrangu/async_event_emitter@2.4.7': {}
'@vladmandic/face-api@1.7.15': {}
'@vue/compiler-core@3.4.21': '@vue/compiler-core@3.4.21':
dependencies: dependencies:
'@babel/parser': 7.29.0 '@babel/parser': 7.29.0
@@ -12054,6 +12293,8 @@ snapshots:
'@webassemblyjs/ast': 1.14.1 '@webassemblyjs/ast': 1.14.1
'@xtuc/long': 4.2.2 '@xtuc/long': 4.2.2
'@webgpu/types@0.1.38': {}
'@xtuc/ieee754@1.2.0': {} '@xtuc/ieee754@1.2.0': {}
'@xtuc/long@4.2.2': {} '@xtuc/long@4.2.2': {}
@@ -12417,6 +12658,11 @@ snapshots:
caniuse-lite@1.0.30001769: {} caniuse-lite@1.0.30001769: {}
canvas@3.2.1:
dependencies:
node-addon-api: 7.1.1
prebuild-install: 7.1.3
chai@5.3.3: chai@5.3.3:
dependencies: dependencies:
assertion-error: 2.0.1 assertion-error: 2.0.1
@@ -12499,6 +12745,8 @@ snapshots:
dependencies: dependencies:
readdirp: 4.1.2 readdirp: 4.1.2
chownr@1.1.4: {}
chrome-trace-event@1.0.4: {} chrome-trace-event@1.0.4: {}
ci-info@3.9.0: {} ci-info@3.9.0: {}
@@ -12530,6 +12778,12 @@ snapshots:
client-only@0.0.1: {} client-only@0.0.1: {}
cliui@7.0.4:
dependencies:
string-width: 4.2.3
strip-ansi: 6.0.1
wrap-ansi: 7.0.0
cliui@8.0.1: cliui@8.0.1:
dependencies: dependencies:
string-width: 4.2.3 string-width: 4.2.3
@@ -12611,6 +12865,8 @@ snapshots:
cookie@0.7.2: {} cookie@0.7.2: {}
core-js@3.29.1: {}
cosmiconfig-typescript-loader@6.2.0(@types/node@20.19.33)(cosmiconfig@9.0.0(typescript@5.9.3))(typescript@5.9.3): cosmiconfig-typescript-loader@6.2.0(@types/node@20.19.33)(cosmiconfig@9.0.0(typescript@5.9.3))(typescript@5.9.3):
dependencies: dependencies:
'@types/node': 20.19.33 '@types/node': 20.19.33
@@ -12635,7 +12891,7 @@ snapshots:
optionalDependencies: optionalDependencies:
typescript: 5.9.3 typescript: 5.9.3
crawlee@3.16.0(@types/node@22.19.10)(playwright@1.58.2): crawlee@3.16.0(@types/node@22.19.10)(canvas@3.2.1)(playwright@1.58.2):
dependencies: dependencies:
'@crawlee/basic': 3.16.0 '@crawlee/basic': 3.16.0
'@crawlee/browser': 3.16.0(playwright@1.58.2) '@crawlee/browser': 3.16.0(playwright@1.58.2)
@@ -12644,8 +12900,8 @@ snapshots:
'@crawlee/cli': 3.16.0(@types/node@22.19.10) '@crawlee/cli': 3.16.0(@types/node@22.19.10)
'@crawlee/core': 3.16.0 '@crawlee/core': 3.16.0
'@crawlee/http': 3.16.0 '@crawlee/http': 3.16.0
'@crawlee/jsdom': 3.16.0 '@crawlee/jsdom': 3.16.0(canvas@3.2.1)
'@crawlee/linkedom': 3.16.0 '@crawlee/linkedom': 3.16.0(canvas@3.2.1)
'@crawlee/playwright': 3.16.0(playwright@1.58.2) '@crawlee/playwright': 3.16.0(playwright@1.58.2)
'@crawlee/puppeteer': 3.16.0(playwright@1.58.2) '@crawlee/puppeteer': 3.16.0(playwright@1.58.2)
'@crawlee/utils': 3.16.0 '@crawlee/utils': 3.16.0
@@ -12832,8 +13088,14 @@ snapshots:
dependencies: dependencies:
mimic-response: 4.0.0 mimic-response: 4.0.0
decompress-response@6.0.0:
dependencies:
mimic-response: 3.1.0
deep-eql@5.0.2: {} deep-eql@5.0.2: {}
deep-extend@0.6.0: {}
deep-is@0.1.4: {} deep-is@0.1.4: {}
deepmerge@4.3.1: {} deepmerge@4.3.1: {}
@@ -13482,6 +13744,8 @@ snapshots:
signal-exit: 3.0.7 signal-exit: 3.0.7
strip-final-newline: 3.0.0 strip-final-newline: 3.0.0
expand-template@2.0.3: {}
expect-type@1.3.0: {} expect-type@1.3.0: {}
extendable-error@0.1.7: {} extendable-error@0.1.7: {}
@@ -13699,6 +13963,8 @@ snapshots:
from@0.1.7: {} from@0.1.7: {}
fs-constants@1.0.0: {}
fs-extra@10.1.0: fs-extra@10.1.0:
dependencies: dependencies:
graceful-fs: 4.2.11 graceful-fs: 4.2.11
@@ -13808,6 +14074,8 @@ snapshots:
meow: 12.1.1 meow: 12.1.1
split2: 4.2.0 split2: 4.2.0
github-from-package@0.0.0: {}
glob-parent@5.1.2: glob-parent@5.1.2:
dependencies: dependencies:
is-glob: 4.0.3 is-glob: 4.0.3
@@ -14103,6 +14371,8 @@ snapshots:
inherits@2.0.4: {} inherits@2.0.4: {}
ini@1.3.8: {}
ini@4.1.1: {} ini@4.1.1: {}
inquirer@8.2.7(@types/node@22.19.10): inquirer@8.2.7(@types/node@22.19.10):
@@ -14388,7 +14658,7 @@ snapshots:
dependencies: dependencies:
argparse: 2.0.1 argparse: 2.0.1
jsdom@26.1.0: jsdom@26.1.0(canvas@3.2.1):
dependencies: dependencies:
cssstyle: 4.6.0 cssstyle: 4.6.0
data-urls: 5.0.0 data-urls: 5.0.0
@@ -14410,12 +14680,14 @@ snapshots:
whatwg-url: 14.2.0 whatwg-url: 14.2.0
ws: 8.19.0 ws: 8.19.0
xml-name-validator: 5.0.0 xml-name-validator: 5.0.0
optionalDependencies:
canvas: 3.2.1
transitivePeerDependencies: transitivePeerDependencies:
- bufferutil - bufferutil
- supports-color - supports-color
- utf-8-validate - utf-8-validate
jsdom@27.4.0: jsdom@27.4.0(canvas@3.2.1):
dependencies: dependencies:
'@acemir/cssom': 0.9.31 '@acemir/cssom': 0.9.31
'@asamuzakjp/dom-selector': 6.7.8 '@asamuzakjp/dom-selector': 6.7.8
@@ -14437,6 +14709,8 @@ snapshots:
whatwg-url: 15.1.0 whatwg-url: 15.1.0
ws: 8.19.0 ws: 8.19.0
xml-name-validator: 5.0.0 xml-name-validator: 5.0.0
optionalDependencies:
canvas: 3.2.1
transitivePeerDependencies: transitivePeerDependencies:
- '@noble/hashes' - '@noble/hashes'
- bufferutil - bufferutil
@@ -14593,13 +14867,15 @@ snapshots:
lines-and-columns@1.2.4: {} lines-and-columns@1.2.4: {}
linkedom@0.18.12: linkedom@0.18.12(canvas@3.2.1):
dependencies: dependencies:
css-select: 5.2.2 css-select: 5.2.2
cssom: 0.5.0 cssom: 0.5.0
html-escaper: 3.0.3 html-escaper: 3.0.3
htmlparser2: 10.1.0 htmlparser2: 10.1.0
uhyphen: 0.2.0 uhyphen: 0.2.0
optionalDependencies:
canvas: 3.2.1
lint-staged@16.2.7: lint-staged@16.2.7:
dependencies: dependencies:
@@ -14674,6 +14950,8 @@ snapshots:
strip-ansi: 7.1.2 strip-ansi: 7.1.2
wrap-ansi: 9.0.2 wrap-ansi: 9.0.2
long@4.0.0: {}
loose-envify@1.4.0: loose-envify@1.4.0:
dependencies: dependencies:
js-tokens: 4.0.0 js-tokens: 4.0.0
@@ -14752,6 +15030,8 @@ snapshots:
mimic-function@5.0.1: {} mimic-function@5.0.1: {}
mimic-response@3.1.0: {}
mimic-response@4.0.0: {} mimic-response@4.0.0: {}
min-indent@1.0.1: {} min-indent@1.0.1: {}
@@ -14772,6 +15052,8 @@ snapshots:
minipass@7.1.2: {} minipass@7.1.2: {}
mkdirp-classic@0.5.3: {}
ml-array-max@1.2.4: ml-array-max@1.2.4:
dependencies: dependencies:
is-any-array: 2.0.1 is-any-array: 2.0.1
@@ -14835,6 +15117,8 @@ snapshots:
nanoid@5.0.6: {} nanoid@5.0.6: {}
napi-build-utils@2.0.0: {}
napi-postinstall@0.3.4: {} napi-postinstall@0.3.4: {}
natural-compare@1.4.0: {} natural-compare@1.4.0: {}
@@ -14888,10 +15172,18 @@ snapshots:
- '@babel/core' - '@babel/core'
- babel-plugin-macros - babel-plugin-macros
node-abi@3.87.0:
dependencies:
semver: 7.7.4
node-addon-api@7.1.1: {} node-addon-api@7.1.1: {}
node-domexception@1.0.0: {} node-domexception@1.0.0: {}
node-fetch@2.6.13:
dependencies:
whatwg-url: 5.0.0
node-fetch@2.7.0: node-fetch@2.7.0:
dependencies: dependencies:
whatwg-url: 5.0.0 whatwg-url: 5.0.0
@@ -15536,6 +15828,21 @@ snapshots:
dependencies: dependencies:
xtend: 4.0.2 xtend: 4.0.2
prebuild-install@7.1.3:
dependencies:
detect-libc: 2.1.2
expand-template: 2.0.3
github-from-package: 0.0.0
minimist: 1.2.8
mkdirp-classic: 0.5.3
napi-build-utils: 2.0.0
node-abi: 3.87.0
pump: 3.0.3
rc: 1.2.8
simple-get: 4.0.1
tar-fs: 2.1.4
tunnel-agent: 0.6.0
prelude-ls@1.2.1: {} prelude-ls@1.2.1: {}
prettier@2.8.8: {} prettier@2.8.8: {}
@@ -15625,6 +15932,13 @@ snapshots:
dependencies: dependencies:
safe-buffer: 5.2.1 safe-buffer: 5.2.1
rc@1.2.8:
dependencies:
deep-extend: 0.6.0
ini: 1.3.8
minimist: 1.2.8
strip-json-comments: 2.0.1
react-dom@19.2.4(react@19.2.4): react-dom@19.2.4(react@19.2.4):
dependencies: dependencies:
react: 19.2.4 react: 19.2.4
@@ -15696,6 +16010,8 @@ snapshots:
get-proto: 1.0.1 get-proto: 1.0.1
which-builtin-type: 1.2.1 which-builtin-type: 1.2.1
regenerator-runtime@0.13.11: {}
regexp.prototype.flags@1.5.4: regexp.prototype.flags@1.5.4:
dependencies: dependencies:
call-bind: 1.0.8 call-bind: 1.0.8
@@ -15917,6 +16233,8 @@ snapshots:
secure-json-parse@4.1.0: {} secure-json-parse@4.1.0: {}
seedrandom@3.0.5: {}
selderee@0.11.0: selderee@0.11.0:
dependencies: dependencies:
parseley: 0.12.1 parseley: 0.12.1
@@ -16051,6 +16369,14 @@ snapshots:
signal-exit@4.1.0: {} signal-exit@4.1.0: {}
simple-concat@1.0.1: {}
simple-get@4.0.1:
dependencies:
decompress-response: 6.0.0
once: 1.4.0
simple-concat: 1.0.1
simple-swizzle@0.2.4: simple-swizzle@0.2.4:
dependencies: dependencies:
is-arrayish: 0.3.4 is-arrayish: 0.3.4
@@ -16252,6 +16578,8 @@ snapshots:
dependencies: dependencies:
min-indent: 1.0.1 min-indent: 1.0.1
strip-json-comments@2.0.1: {}
strip-json-comments@3.1.1: {} strip-json-comments@3.1.1: {}
strip-json-comments@5.0.3: {} strip-json-comments@5.0.3: {}
@@ -16345,6 +16673,21 @@ snapshots:
tapable@2.3.0: {} tapable@2.3.0: {}
tar-fs@2.1.4:
dependencies:
chownr: 1.1.4
mkdirp-classic: 0.5.3
pump: 3.0.3
tar-stream: 2.2.0
tar-stream@2.2.0:
dependencies:
bl: 4.1.0
end-of-stream: 1.4.5
fs-constants: 1.0.0
inherits: 2.0.4
readable-stream: 3.6.2
tarn@3.0.2: {} tarn@3.0.2: {}
term-size@2.2.1: {} term-size@2.2.1: {}
@@ -16529,6 +16872,10 @@ snapshots:
optionalDependencies: optionalDependencies:
fsevents: 2.3.3 fsevents: 2.3.3
tunnel-agent@0.6.0:
dependencies:
safe-buffer: 5.2.1
type-check@0.4.0: type-check@0.4.0:
dependencies: dependencies:
prelude-ls: 1.2.1 prelude-ls: 1.2.1
@@ -16770,7 +17117,7 @@ snapshots:
tsx: 4.21.0 tsx: 4.21.0
yaml: 2.8.2 yaml: 2.8.2
vitest@2.1.9(@types/node@22.19.10)(@vitest/ui@4.0.18)(happy-dom@20.5.3)(jsdom@27.4.0)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0): vitest@2.1.9(@types/node@22.19.10)(@vitest/ui@4.0.18)(happy-dom@20.5.3)(jsdom@27.4.0(canvas@3.2.1))(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0):
dependencies: dependencies:
'@vitest/expect': 2.1.9 '@vitest/expect': 2.1.9
'@vitest/mocker': 2.1.9(vite@5.4.21(@types/node@22.19.10)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)) '@vitest/mocker': 2.1.9(vite@5.4.21(@types/node@22.19.10)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0))
@@ -16796,7 +17143,7 @@ snapshots:
'@types/node': 22.19.10 '@types/node': 22.19.10
'@vitest/ui': 4.0.18(vitest@4.0.18) '@vitest/ui': 4.0.18(vitest@4.0.18)
happy-dom: 20.5.3 happy-dom: 20.5.3
jsdom: 27.4.0 jsdom: 27.4.0(canvas@3.2.1)
transitivePeerDependencies: transitivePeerDependencies:
- less - less
- lightningcss - lightningcss
@@ -16808,7 +17155,7 @@ snapshots:
- supports-color - supports-color
- terser - terser
vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.10)(@vitest/ui@4.0.18)(happy-dom@20.5.3)(jsdom@27.4.0)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0): vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.10)(@vitest/ui@4.0.18)(happy-dom@20.5.3)(jsdom@27.4.0(canvas@3.2.1))(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0):
dependencies: dependencies:
'@types/chai': 5.2.3 '@types/chai': 5.2.3
'@vitest/expect': 3.2.4 '@vitest/expect': 3.2.4
@@ -16838,7 +17185,7 @@ snapshots:
'@types/node': 22.19.10 '@types/node': 22.19.10
'@vitest/ui': 4.0.18(vitest@4.0.18) '@vitest/ui': 4.0.18(vitest@4.0.18)
happy-dom: 20.5.3 happy-dom: 20.5.3
jsdom: 27.4.0 jsdom: 27.4.0(canvas@3.2.1)
transitivePeerDependencies: transitivePeerDependencies:
- less - less
- lightningcss - lightningcss
@@ -16850,7 +17197,7 @@ snapshots:
- supports-color - supports-color
- terser - terser
vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@20.19.33)(@vitest/ui@4.0.18)(happy-dom@20.5.3)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2): vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@20.19.33)(@vitest/ui@4.0.18)(happy-dom@20.5.3)(jiti@2.6.1)(jsdom@27.4.0(canvas@3.2.1))(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2):
dependencies: dependencies:
'@vitest/expect': 4.0.18 '@vitest/expect': 4.0.18
'@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@20.19.33)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@20.19.33)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))
@@ -16877,7 +17224,7 @@ snapshots:
'@types/node': 20.19.33 '@types/node': 20.19.33
'@vitest/ui': 4.0.18(vitest@4.0.18) '@vitest/ui': 4.0.18(vitest@4.0.18)
happy-dom: 20.5.3 happy-dom: 20.5.3
jsdom: 27.4.0 jsdom: 27.4.0(canvas@3.2.1)
transitivePeerDependencies: transitivePeerDependencies:
- jiti - jiti
- less - less
@@ -17133,8 +17480,20 @@ snapshots:
figlet: 1.10.0 figlet: 1.10.0
parent-require: 1.0.0 parent-require: 1.0.0
yargs-parser@20.2.9: {}
yargs-parser@21.1.1: {} yargs-parser@21.1.1: {}
yargs@16.2.0:
dependencies:
cliui: 7.0.4
escalade: 3.2.0
get-caller-file: 2.0.5
require-directory: 2.1.1
string-width: 4.2.3
y18n: 5.0.8
yargs-parser: 20.2.9
yargs@17.7.2: yargs@17.7.2:
dependencies: dependencies:
cliui: 8.0.1 cliui: 8.0.1