Compare commits

..

3 Commits

9 changed files with 442 additions and 89 deletions

View File

@@ -1,70 +1,59 @@
# ================================
# Stage 1: Build stage
# ================================
FROM node:22-alpine AS builder
FROM node:22-slim
WORKDIR /build
# Install build dependencies needed for native modules (better-sqlite3)
RUN apk add --no-cache python3 make g++
# Copy package files first for better layer caching
COPY package.json yarn.lock ./
# Install all dependencies (including devDependencies for building)
RUN yarn config set network-timeout 600000 \
&& yarn --frozen-lockfile
# Copy source files needed for build
COPY index.html vite.config.js ./
COPY ui ./ui
COPY lib ./lib
# Build frontend assets
RUN yarn build:frontend
# ================================
# Stage 2: Production stage
# ================================
FROM node:22-alpine
# System deps for Chrome for Testing + build tools for native modules (better-sqlite3)
# Must run as root
RUN apt-get update && apt-get install -y --no-install-recommends \
curl ca-certificates fonts-liberation libasound2 \
libatk-bridge2.0-0 libatk1.0-0 libcups2 libdbus-1-3 \
libdrm2 libgbm1 libgtk-3-0 libnspr4 libnss3 \
libx11-xcb1 libxcomposite1 libxdamage1 libxrandr2 xdg-utils \
python3 make g++ \
&& rm -rf /var/lib/apt/lists/* \
&& mkdir -p /db /conf /fredy \
&& chown node:node /db /conf /fredy
WORKDIR /fredy
# Install Chromium and curl (for healthcheck)
# Using Alpine's chromium package which is much smaller
RUN apk add --no-cache chromium curl
# Everything from here runs as the built-in non-root node user (UID 1000)
USER node
ENV NODE_ENV=production \
IS_DOCKER=true \
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true \
PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser
IS_DOCKER=true
# Install build dependencies for native modules, then remove them after yarn install
COPY package.json yarn.lock ./
COPY --chown=node:node package.json yarn.lock ./
RUN apk add --no-cache --virtual .build-deps python3 make g++ \
&& yarn config set network-timeout 600000 \
&& yarn --frozen-lockfile --production \
&& yarn cache clean \
&& apk del .build-deps
# Install dependencies and purge build tools (only needed to compile better-sqlite3)
RUN yarn config set network-timeout 600000 \
&& yarn --frozen-lockfile \
&& yarn cache clean
# Copy built frontend from builder stage
COPY --from=builder /build/ui/public ./ui/public
# Install Chrome for Testing in a separate layer — it's ~150MB and rarely changes,
# so keeping it separate avoids re-downloading on every code/dependency change
RUN npx puppeteer browsers install chrome
# Copy application source (only what's needed at runtime)
COPY index.js ./
COPY index.html ./
COPY lib ./lib
# Purge build tools now that native modules are compiled
USER root
RUN apt-get purge -y python3 make g++ \
&& apt-get autoremove -y \
&& rm -rf /var/lib/apt/lists/*
USER node
# Prepare runtime directories and symlinks for data and config
RUN mkdir -p /db /conf \
&& chown 1000:1000 /db /conf \
&& chmod 777 /db /conf \
&& ln -s /db /fredy/db \
COPY --chown=node:node index.html vite.config.js ./
COPY --chown=node:node ui ./ui
COPY --chown=node:node lib ./lib
RUN yarn build:frontend
COPY --chown=node:node index.js ./
RUN ln -s /db /fredy/db \
&& ln -s /conf /fredy/conf
EXPOSE 9998
VOLUME /db
VOLUME /conf
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
CMD curl -f http://localhost:9998/ || exit 1
CMD ["node", "index.js"]

View File

@@ -7,12 +7,63 @@ if [ "$(docker ps -aq -f name=fredy)" ]; then
docker rm fredy || true
fi
# On Apple Silicon, force linux/amd64 to match production CI and avoid arm64/x86_64
# Chrome mismatch under Rosetta. On native Linux (amd64 or arm64) let Docker pick naturally. That took me fucking 1 hour to figure out.
PLATFORM=""
if [ "$(uname -m)" = "arm64" ] && [ "$(uname -s)" = "Darwin" ]; then
PLATFORM="linux/amd64"
fi
# Build image from local Dockerfile, forcing a fresh build without cache
docker build --no-cache -t fredy:local .
if [ -n "$PLATFORM" ]; then
docker build --no-cache --platform "$PLATFORM" -t fredy:local .
else
docker build --no-cache -t fredy:local .
fi
# Run container with volumes and port mapping
docker run -d --name fredy \
-v fredy_conf:/conf \
-v fredy_db:/db \
-p 9998:9998 \
fredy:local
if [ -n "$PLATFORM" ]; then
docker run -d --name fredy --platform "$PLATFORM" -v fredy_conf:/conf -v fredy_db:/db -p 9998:9998 fredy:local
else
docker run -d --name fredy -v fredy_conf:/conf -v fredy_db:/db -p 9998:9998 fredy:local
fi
echo "Waiting for app to be ready..."
for i in $(seq 1 30); do
if docker exec fredy curl -sf http://localhost:9998/ > /dev/null 2>&1; then
echo "App is up"
break
fi
if [ "$i" = "30" ]; then
echo "App did not come up in time"
docker logs fredy
exit 1
fi
sleep 2
done
# Verify the process is NOT running as root
RUNNING_USER=$(docker exec fredy id -u)
if [ "$RUNNING_USER" = "0" ]; then
echo "Process is running as root!"
exit 1
fi
echo "Process runs as UID $RUNNING_USER (not root)"
# Verify Chrome launches without crashing
echo "Testing Chrome..."
CHROME=$(docker exec fredy find /home/node/.cache/puppeteer -name chrome -type f 2>/dev/null | head -1)
if [ -z "$CHROME" ]; then
echo "Chrome binary not found"
exit 1
fi
if docker exec fredy "$CHROME" --headless --no-sandbox --disable-gpu --dump-dom https://example.com 2>&1 | grep -q "<html"; then
echo "Chrome works"
else
echo "Chrome failed to render a page"
docker exec fredy "$CHROME" --headless --no-sandbox --disable-gpu --dump-dom https://example.com 2>&1 | head -20
exit 1
fi
echo ""
echo "All checks passed."

View File

@@ -1,4 +1,4 @@
# Fredy MCP Server
# Fredy MCP Server
The Fredy MCP Server exposes your real estate jobs and listings data to LLM clients. It supports two transports:
@@ -126,6 +126,54 @@ The LLM will automatically call the appropriate Fredy MCP tools and present the
> **Tip:** Make sure Fredy is running and the database is accessible before starting the MCP server in LM Studio. The stdio transport initializes its own database connection, so Fredy's main process does not need to be running, but the database file must exist and be up-to-date (migrations applied).
### Claude Desktop Configuration
[Claude Desktop](https://claude.ai/download) supports MCP servers natively via its developer settings.
#### Setup
1. Open **Claude Desktop**
2. Go to **Settings → Developer → Edit Config** — this opens the `claude_desktop_config.json` file
3. Add the `fredy` server to the `mcpServers` object:
```json
{
"mcpServers": {
"fredy": {
"command": "/opt/homebrew/opt/node@22/bin/node",
"args": ["/absolute/path/to/fredy/lib/mcp/stdio.js"],
"env": {
"MCP_TOKEN": "fredy_<your-token>"
}
}
}
}
```
Replace `/absolute/path/to/fredy` with the actual path on your machine (e.g. `/Users/you/dev/fredy`).
> **Important:** Claude Desktop launches with a restricted `PATH` and often cannot find `node` by name. Always use the **full absolute path** to the node binary. Find yours by running `which node` in a terminal. Common locations:
> - Homebrew (default): `/opt/homebrew/bin/node`
> - Homebrew (versioned, e.g. node@22): `/opt/homebrew/opt/node@22/bin/node`
> - nvm: `/Users/<you>/.nvm/versions/node/<version>/bin/node`
4. Save the file and **restart Claude Desktop**
5. You should see a hammer icon (🔨) in the chat input — click it to confirm the Fredy tools are listed
#### Usage
Once connected, simply ask Claude about your real estate data:
- *"Show me all my active search jobs"*
- *"List the latest listings from my Berlin apartment search"*
- *"What are the cheapest apartments added this week?"*
Claude will automatically call the appropriate Fredy MCP tools.
> **Note:** Fredy's main web process does not need to be running — the stdio transport opens its own database connection directly. But the SQLite database file must exist and migrations must have been applied.
---
## Usage with Remote LLM (Streamable HTTP transport)
The HTTP transport is automatically available when Fredy is running. It uses the MCP Streamable HTTP protocol at:

View File

@@ -0,0 +1,112 @@
/*
* Copyright (c) 2026 by Christian Kellner.
* Licensed under Apache-2.0 with Commons Clause and Attribution/Naming Clause
*/
import nodemailer from 'nodemailer';
import path from 'path';
import fs from 'fs';
import Handlebars from 'handlebars';
import { markdown2Html } from '../../services/markdown.js';
import { getDirName, normalizeImageUrl } from '../../utils.js';
const __dirname = getDirName();
const template = fs.readFileSync(path.resolve(__dirname + '/notification/emailTemplate/template.hbs'), 'utf8');
const emailTemplate = Handlebars.compile(template);
const mapListings = (serviceName, jobKey, listings) =>
listings.map((l) => {
const image = normalizeImageUrl(l.image);
return {
title: l.title || '',
link: l.link || '',
address: l.address || '',
size: l.size || '',
price: l.price || '',
image,
hasImage: Boolean(image),
serviceName,
jobKey,
};
});
export const send = async ({ serviceName, newListings, notificationConfig, jobKey }) => {
const { host, port, secure, username, password, receiver, from } = notificationConfig.find(
(adapter) => adapter.id === config.id,
).fields;
const to = receiver
.trim()
.split(',')
.map((r) => r.trim())
.filter(Boolean);
const transporter = nodemailer.createTransport({
host,
port: Number(port),
secure: secure === 'true',
auth: {
user: username,
pass: password,
},
});
const listings = mapListings(serviceName, jobKey, newListings);
const html = emailTemplate({
serviceName: `Job: (${jobKey}) | Service: ${serviceName}`,
numberOfListings: listings.length,
listings,
});
return transporter.sendMail({
from,
to: to.join(','),
subject: `Fredy found ${listings.length} new listing(s) for ${serviceName}`,
html,
});
};
export const config = {
id: 'smtp',
name: 'SMTP',
description: 'Send notifications via any SMTP server using Nodemailer.',
readme: markdown2Html('lib/notification/adapter/smtp.md'),
fields: {
host: {
type: 'text',
label: 'SMTP Host',
description: 'The hostname of the SMTP server (e.g., smtp.gmail.com).',
},
port: {
type: 'text',
label: 'SMTP Port',
description: 'The port of the SMTP server (e.g., 587 for STARTTLS, 465 for SSL).',
},
secure: {
type: 'text',
label: 'Secure (SSL/TLS)',
description: 'Set to "true" for port 465 (SSL). Leave empty or "false" for STARTTLS on port 587.',
},
username: {
type: 'text',
label: 'Username',
description: 'The username for SMTP authentication.',
},
password: {
type: 'text',
label: 'Password',
description: 'The password (or app password) for SMTP authentication.',
},
receiver: {
type: 'text',
label: 'Receiver Email(s)',
description: 'Comma-separated email addresses Fredy will send notifications to.',
},
from: {
type: 'email',
label: 'Sender Email',
description: 'The email address Fredy sends from.',
},
},
};

View File

@@ -0,0 +1,22 @@
### SMTP Adapter
Send notifications through any SMTP server using [Nodemailer](https://nodemailer.com/).
This works with Gmail, Outlook, self-hosted mail servers, or any provider that supports SMTP.
Setup:
- Provide the SMTP host and port of your mail server.
- For **SSL/TLS** (port 465), set Secure to `true`.
- For **STARTTLS** (port 587), leave Secure empty or set it to `false`.
- Enter the username and password for authentication. For Gmail, use an [App Password](https://support.google.com/accounts/answer/185833).
- Set the sender email address (must be allowed by your SMTP server).
Multiple recipients:
- Separate email addresses with commas (e.g., `some@email.com`, `someOther@email.com`).
Common SMTP settings:
- **Gmail** — `smtp.gmail.com`, port 587, secure: false
- **Outlook** — `smtp.office365.com`, port 587, secure: false
- **Yahoo** — `smtp.mail.yahoo.com`, port 465, secure: true

View File

@@ -29,12 +29,12 @@
*/
import fs from 'fs';
import path from 'path';
import { pathToFileURL } from 'url';
import { pathToFileURL, fileURLToPath } from 'url';
import crypto from 'crypto';
import SqliteConnection from '../SqliteConnection.js';
import logger from '../../logger.js';
const ROOT = path.resolve('.');
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..', '..', '..');
/**
* Absolute path to the migrations directory (lib/services/storage/migrations/sql).
* @type {string}

View File

@@ -1,6 +1,6 @@
{
"name": "fredy",
"version": "20.0.5",
"version": "20.0.7",
"description": "[F]ind [R]eal [E]states [d]amn eas[y].",
"scripts": {
"prepare": "husky",
@@ -77,14 +77,15 @@
"cookie-session": "2.1.1",
"handlebars": "4.7.8",
"lodash": "4.17.23",
"maplibre-gl": "^5.20.1",
"maplibre-gl": "^5.20.2",
"nanoid": "5.1.7",
"node-cron": "^4.2.1",
"node-fetch": "3.3.2",
"node-mailjet": "6.0.11",
"nodemailer": "^8.0.3",
"p-throttle": "^8.1.0",
"package-up": "^5.0.0",
"puppeteer": "^24.39.1",
"puppeteer": "^24.40.0",
"puppeteer-extra": "^3.3.6",
"puppeteer-extra-plugin-stealth": "^2.11.2",
"query-string": "9.3.1",
@@ -99,7 +100,7 @@
"semver": "^7.7.4",
"serve-static": "2.2.1",
"slack": "11.0.2",
"vite": "8.0.0",
"vite": "8.0.1",
"x-var": "^3.0.1",
"zustand": "^5.0.12"
},

View File

@@ -158,11 +158,11 @@ export default function NotificationAdapterMutator({
{uiElement.type === 'boolean' ? (
<div style={{ display: 'flex', alignItems: 'center', gap: '16px' }}>
<Switch
checked={uiElement.value || false}
onChange={(checked) => {
setValue(selectedAdapter, uiElement, key, checked);
}}
/>
checked={uiElement.value || false}
onChange={(checked) => {
setValue(selectedAdapter, uiElement, key, checked);
}}
/>
{uiElement.label}
</div>
) : (
@@ -173,6 +173,7 @@ export default function NotificationAdapterMutator({
initValue={uiElement.value ?? ''}
placeholder={uiElement.label}
label={uiElement.label}
extraText={uiElement.description}
onChange={(value) => {
setValue(selectedAdapter, uiElement, key, value);
}}

167
yarn.lock
View File

@@ -1276,10 +1276,10 @@
resolved "https://registry.npmjs.org/@maplibre/geojson-vt/-/geojson-vt-5.0.4.tgz"
integrity sha512-KGg9sma45S+stfH9vPCJk1J0lSDLWZgCT9Y8u8qWZJyjFlP8MNP1WGTxIMYJZjDvVT3PDn05kN1C95Sut1HpgQ==
"@maplibre/geojson-vt@^6.0.2":
version "6.0.3"
resolved "https://registry.yarnpkg.com/@maplibre/geojson-vt/-/geojson-vt-6.0.3.tgz#1167caa068468b39989e8be272e3200831de7bab"
integrity sha512-tJ8df2SAIacER7pWTiSlDjIULBBAfZnzAURvWb1d8kVzx/pmSJcG0L2p0DTAB6nEu8Lmsx5zAc8JFDcs2DTwaw==
"@maplibre/geojson-vt@^6.0.3":
version "6.0.4"
resolved "https://registry.yarnpkg.com/@maplibre/geojson-vt/-/geojson-vt-6.0.4.tgz#f028fa633594c067b4c24030c1c282c0dd6cc835"
integrity sha512-HYv3POhMRCdhP3UPPATM/hfcy6/WuVIf5FKboH8u/ZuFMTnAIcSVlq5nfOqroLokd925w2QtE7YwquFOIacwVQ==
dependencies:
kdbush "^4.0.2"
@@ -1396,6 +1396,11 @@
resolved "https://registry.yarnpkg.com/@oxc-project/types/-/types-0.115.0.tgz#92a599543529bce45f8f2da77f40a124d63349dc"
integrity sha512-4n91DKnebUS4yjUHl2g3/b2T+IUdCfmoZGhmwsovZCDaJSs+QkVAM+0AqqTxHSsHfeiMuueT75cZaZcT/m0pSw==
"@oxc-project/types@=0.120.0":
version "0.120.0"
resolved "https://registry.yarnpkg.com/@oxc-project/types/-/types-0.120.0.tgz#af521b0e689dd0eaa04fe4feef9b68d98b74783d"
integrity sha512-k1YNu55DuvAip/MGE1FTsIuU3FUCn6v/ujG9V7Nq5Df/kX2CWb13hhwD0lmJGMGqE+bE1MXvv9SZVnMzEXlWcg==
"@puppeteer/browsers@2.13.0":
version "2.13.0"
resolved "https://registry.yarnpkg.com/@puppeteer/browsers/-/browsers-2.13.0.tgz#10f980c6d65efeff77f8a3cac6e1a7ac10604500"
@@ -1414,66 +1419,133 @@
resolved "https://registry.npmjs.org/@remirror/core-constants/-/core-constants-3.0.0.tgz"
integrity sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==
"@rolldown/binding-android-arm64@1.0.0-rc.10":
version "1.0.0-rc.10"
resolved "https://registry.yarnpkg.com/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.10.tgz#0bbd3380f49a6d0dc96c9b32fb7dad26ae0dfaa7"
integrity sha512-jOHxwXhxmFKuXztiu1ORieJeTbx5vrTkcOkkkn2d35726+iwhrY1w/+nYY/AGgF12thg33qC3R1LMBF5tHTZHg==
"@rolldown/binding-android-arm64@1.0.0-rc.9":
version "1.0.0-rc.9"
resolved "https://registry.yarnpkg.com/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.9.tgz#4bbd28868564948c2bf04b3ca117a6828f95626c"
integrity sha512-lcJL0bN5hpgJfSIz/8PIf02irmyL43P+j1pTCfbD1DbLkmGRuFIA4DD3B3ZOvGqG0XiVvRznbKtN0COQVaKUTg==
"@rolldown/binding-darwin-arm64@1.0.0-rc.10":
version "1.0.0-rc.10"
resolved "https://registry.yarnpkg.com/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.10.tgz#a30b051784fbb13635e652ba4041c6ce7a4ce7ab"
integrity sha512-gED05Teg/vtTZbIJBc4VNMAxAFDUPkuO/rAIyyxZjTj1a1/s6z5TII/5yMGZ0uLRCifEtwUQn8OlYzuYc0m70w==
"@rolldown/binding-darwin-arm64@1.0.0-rc.9":
version "1.0.0-rc.9"
resolved "https://registry.yarnpkg.com/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.9.tgz#80864a6997404f264cc7a216cad221fe6148705d"
integrity sha512-J7Zk3kLYFsLtuH6U+F4pS2sYVzac0qkjcO5QxHS7OS7yZu2LRs+IXo+uvJ/mvpyUljDJ3LROZPoQfgBIpCMhdQ==
"@rolldown/binding-darwin-x64@1.0.0-rc.10":
version "1.0.0-rc.10"
resolved "https://registry.yarnpkg.com/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.10.tgz#2d9dea982d5be90b95b6d8836ff26a4b0959d94b"
integrity sha512-rI15NcM1mA48lqrIxVkHfAqcyFLcQwyXWThy+BQ5+mkKKPvSO26ir+ZDp36AgYoYVkqvMcdS8zOE6SeBsR9e8A==
"@rolldown/binding-darwin-x64@1.0.0-rc.9":
version "1.0.0-rc.9"
resolved "https://registry.yarnpkg.com/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.9.tgz#747b698878b6f44d817f87e9e3cb197b16076d2a"
integrity sha512-iwtmmghy8nhfRGeNAIltcNXzD0QMNaaA5U/NyZc1Ia4bxrzFByNMDoppoC+hl7cDiUq5/1CnFthpT9n+UtfFyg==
"@rolldown/binding-freebsd-x64@1.0.0-rc.10":
version "1.0.0-rc.10"
resolved "https://registry.yarnpkg.com/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.10.tgz#4efc3aca43ae4dfb90729eeca6e84ef6e6b38c4a"
integrity sha512-XZRXHdTa+4ME1MuDVp021+doQ+z6Ei4CCFmNc5/sKbqb8YmkiJdj8QKlV3rCI0AJtAeSB5n0WGPuJWNL9p/L2w==
"@rolldown/binding-freebsd-x64@1.0.0-rc.9":
version "1.0.0-rc.9"
resolved "https://registry.yarnpkg.com/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.9.tgz#35c29d7c83aa75429c74d7d1ee9c7d3e61f4552c"
integrity sha512-DLFYI78SCiZr5VvdEplsVC2Vx53lnA4/Ga5C65iyldMVaErr86aiqCoNBLl92PXPfDtUYjUh+xFFor40ueNs4Q==
"@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.10":
version "1.0.0-rc.10"
resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.10.tgz#4a19a5d24537e925b25e9583b6cd575b2ad9fa27"
integrity sha512-R0SQMRluISSLzFE20sPWYHVmJdDQnRyc/FzSCN72BqQmh2SOZUFG+N3/vBZpR4C6WpEUVYJLrYUXaj43sJsNLA==
"@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.9":
version "1.0.0-rc.9"
resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.9.tgz#36d2bcbcf07f17f18fb2df727a62f16e5295c816"
integrity sha512-CsjTmTwd0Hri6iTw/DRMK7kOZ7FwAkrO4h8YWKoX/kcj833e4coqo2wzIFywtch/8Eb5enQ/lwLM7w6JX1W5RQ==
"@rolldown/binding-linux-arm64-gnu@1.0.0-rc.10":
version "1.0.0-rc.10"
resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.10.tgz#01a41e5e905838353ae9a3da10dc8242dcd61453"
integrity sha512-Y1reMrV/o+cwpduYhJuOE3OMKx32RMYCidf14y+HssARRmhDuWXJ4yVguDg2R/8SyyGNo+auzz64LnPK9Hq6jg==
"@rolldown/binding-linux-arm64-gnu@1.0.0-rc.9":
version "1.0.0-rc.9"
resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.9.tgz#5b03c11f2b661a275f2d7628e4f456783e1b9f63"
integrity sha512-2x9O2JbSPxpxMDhP9Z74mahAStibTlrBMW0520+epJH5sac7/LwZW5Bmg/E6CXuEF53JJFW509uP+lSedaUNxg==
"@rolldown/binding-linux-arm64-musl@1.0.0-rc.10":
version "1.0.0-rc.10"
resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.10.tgz#bd059e5f83471de29ce35b0ba254995d8091ca40"
integrity sha512-vELN+HNb2IzuzSBUOD4NHmP9yrGwl1DVM29wlQvx1OLSclL0NgVWnVDKl/8tEks79EFek/kebQKnNJkIAA4W2g==
"@rolldown/binding-linux-arm64-musl@1.0.0-rc.9":
version "1.0.0-rc.9"
resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.9.tgz#d3cbd1b1760d34b5789af89f4bcc09a1446d3eb5"
integrity sha512-JA1QRW31ogheAIRhIg9tjMfsYbglXXYGNPLdPEYrwFxdbkQCAzvpSCSHCDWNl4hTtrol8WeboCSEpjdZK8qrCg==
"@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.10":
version "1.0.0-rc.10"
resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.10.tgz#fe726a540631015f269a989c0cfb299283190390"
integrity sha512-ZqrufYTgzxbHwpqOjzSsb0UV/aV2TFIY5rP8HdsiPTv/CuAgCRjM6s9cYFwQ4CNH+hf9Y4erHW1GjZuZ7WoI7w==
"@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.9":
version "1.0.0-rc.9"
resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.9.tgz#8e971e7f066b2c0876e20c9f6174d645f31efb84"
integrity sha512-aOKU9dJheda8Kj8Y3w9gnt9QFOO+qKPAl8SWd7JPHP+Cu0EuDAE5wokQubLzIDQWg2myXq2XhTpOVS07qqvT+w==
"@rolldown/binding-linux-s390x-gnu@1.0.0-rc.10":
version "1.0.0-rc.10"
resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.10.tgz#825ced028bad3f1fa9ce83b1f3dac76e0424367f"
integrity sha512-gSlmVS1FZJSRicA6IyjoRoKAFK7IIHBs7xJuHRSmjImqk3mPPWbR7RhbnfH2G6bcmMEllCt2vQ/7u9e6bBnByg==
"@rolldown/binding-linux-s390x-gnu@1.0.0-rc.9":
version "1.0.0-rc.9"
resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.9.tgz#e7283523780741f07a4441c7c8af5b2550faadf2"
integrity sha512-OalO94fqj7IWRn3VdXWty75jC5dk4C197AWEuMhIpvVv2lw9fiPhud0+bW2ctCxb3YoBZor71QHbY+9/WToadA==
"@rolldown/binding-linux-x64-gnu@1.0.0-rc.10":
version "1.0.0-rc.10"
resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.10.tgz#b700dae69274aa3d54a16ca5e00e30f47a089119"
integrity sha512-eOCKUpluKgfObT2pHjztnaWEIbUabWzk3qPZ5PuacuPmr4+JtQG4k2vGTY0H15edaTnicgU428XW/IH6AimcQw==
"@rolldown/binding-linux-x64-gnu@1.0.0-rc.9":
version "1.0.0-rc.9"
resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.9.tgz#da2302e079bb5f3a98edf75608621e94f1fb550e"
integrity sha512-cVEl1vZtBsBZna3YMjGXNvnYYrOJ7RzuWvZU0ffvJUexWkukMaDuGhUXn0rjnV0ptzGVkvc+vW9Yqy6h8YX4pg==
"@rolldown/binding-linux-x64-musl@1.0.0-rc.10":
version "1.0.0-rc.10"
resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.10.tgz#eb875660ad68a2348acab36a7005699e87f6e9dd"
integrity sha512-Xdf2jQbfQowJnLcgYfD/m0Uu0Qj5OdxKallD78/IPPfzaiaI4KRAwZzHcKQ4ig1gtg1SuzC7jovNiM2TzQsBXA==
"@rolldown/binding-linux-x64-musl@1.0.0-rc.9":
version "1.0.0-rc.9"
resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.9.tgz#3f27a620d56b93644fd1b6fad58fc2dbe93d5d71"
integrity sha512-UzYnKCIIc4heAKgI4PZ3dfBGUZefGCJ1TPDuLHoCzgrMYPb5Rv6TLFuYtyM4rWyHM7hymNdsg5ik2C+UD9VDbA==
"@rolldown/binding-openharmony-arm64@1.0.0-rc.10":
version "1.0.0-rc.10"
resolved "https://registry.yarnpkg.com/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.10.tgz#72aa24b412f83025087bcf83ce09634b2bd93c5c"
integrity sha512-o1hYe8hLi1EY6jgPFyxQgQ1wcycX+qz8eEbVmot2hFkgUzPxy9+kF0u0NIQBeDq+Mko47AkaFFaChcvZa9UX9Q==
"@rolldown/binding-openharmony-arm64@1.0.0-rc.9":
version "1.0.0-rc.9"
resolved "https://registry.yarnpkg.com/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.9.tgz#9c307777157d029aaf8db1a09221b9275dbe5547"
integrity sha512-+6zoiF+RRyf5cdlFQP7nm58mq7+/2PFaY2DNQeD4B87N36JzfF/l9mdBkkmTvSYcYPE8tMh/o3cRlsx1ldLfog==
"@rolldown/binding-wasm32-wasi@1.0.0-rc.10":
version "1.0.0-rc.10"
resolved "https://registry.yarnpkg.com/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.10.tgz#7f3303a96c5dc01d1f4c539b1dcbc16392c6f17d"
integrity sha512-Ugv9o7qYJudqQO5Y5y2N2SOo6S4WiqiNOpuQyoPInnhVzCY+wi/GHltcLHypG9DEUYMB0iTB/huJrpadiAcNcA==
dependencies:
"@napi-rs/wasm-runtime" "^1.1.1"
"@rolldown/binding-wasm32-wasi@1.0.0-rc.9":
version "1.0.0-rc.9"
resolved "https://registry.yarnpkg.com/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.9.tgz#c3a82bef0ddd644efa74c050c26223f29f55039c"
@@ -1481,16 +1553,31 @@
dependencies:
"@napi-rs/wasm-runtime" "^1.1.1"
"@rolldown/binding-win32-arm64-msvc@1.0.0-rc.10":
version "1.0.0-rc.10"
resolved "https://registry.yarnpkg.com/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.10.tgz#3419144a04ad12c69c48536b01fc21ac9d87ecf4"
integrity sha512-7UODQb4fQUNT/vmgDZBl3XOBAIOutP5R3O/rkxg0aLfEGQ4opbCgU5vOw/scPe4xOqBwL9fw7/RP1vAMZ6QlAQ==
"@rolldown/binding-win32-arm64-msvc@1.0.0-rc.9":
version "1.0.0-rc.9"
resolved "https://registry.yarnpkg.com/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.9.tgz#27e23cbd53b7095d0b66191ef999327b4684a6cf"
integrity sha512-lHVNUG/8nlF1IQk1C0Ci574qKYyty2goMiPlRqkC5R+3LkXDkL5Dhx8ytbxq35m+pkHVIvIxviD+TWLdfeuadA==
"@rolldown/binding-win32-x64-msvc@1.0.0-rc.10":
version "1.0.0-rc.10"
resolved "https://registry.yarnpkg.com/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.10.tgz#09bee46e6a32c6086beeabc3da12e67be714f882"
integrity sha512-PYxKHMVHOb5NJuDL53vBUl1VwUjymDcYI6rzpIni0C9+9mTiJedvUxSk7/RPp7OOAm3v+EjgMu9bIy3N6b408w==
"@rolldown/binding-win32-x64-msvc@1.0.0-rc.9":
version "1.0.0-rc.9"
resolved "https://registry.yarnpkg.com/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.9.tgz#96046309142b398c9c2a9a0a052e7355535e69c8"
integrity sha512-G0oA4+w1iY5AGi5HcDTxWsoxF509hrFIPB2rduV5aDqS9FtDg1CAfa7V34qImbjfhIcA8C+RekocJZA96EarwQ==
"@rolldown/pluginutils@1.0.0-rc.10":
version "1.0.0-rc.10"
resolved "https://registry.yarnpkg.com/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.10.tgz#eed997f37f928a3300bbe2161f42687d8a3ae759"
integrity sha512-UkVDEFk1w3mveXeKgaTuYfKWtPbvgck1dT8TUG3bnccrH0XtLTuAyfCoks4Q/M5ZGToSVJTIQYCzy2g/atAOeg==
"@rolldown/pluginutils@1.0.0-rc.7":
version "1.0.0-rc.7"
resolved "https://registry.yarnpkg.com/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.7.tgz#0414869467f0e471a6515d4f506c85fde867e022"
@@ -4901,10 +4988,10 @@ make-dir@^2.1.0:
pify "^4.0.1"
semver "^5.6.0"
maplibre-gl@^5.20.1:
version "5.20.1"
resolved "https://registry.yarnpkg.com/maplibre-gl/-/maplibre-gl-5.20.1.tgz#6903c4085fd383bf2167edcb2b7fcc5f6dfbf4b1"
integrity sha512-57YIgfRct+rrk78ldoWRuLWRnXV/1vM2Rk0QYfEDQmsXdpgbACwvGoREIOZtyDIaq/GJK/ORYEriaAdVZuNfvw==
maplibre-gl@^5.20.2:
version "5.20.2"
resolved "https://registry.yarnpkg.com/maplibre-gl/-/maplibre-gl-5.20.2.tgz#9dec242f0858f3bc30fd5c44404ed9e23e63adaf"
integrity sha512-0UzMWOe+GZmIUmOA99yTI1vRh15YcGnHxADVB2s+JF3etpjj2/MBCqbPEuu4BP9mLsJWJcpHH0Nzr9uuimmbuQ==
dependencies:
"@mapbox/jsonlint-lines-primitives" "^2.0.2"
"@mapbox/point-geometry" "^1.1.0"
@@ -4912,7 +4999,7 @@ maplibre-gl@^5.20.1:
"@mapbox/unitbezier" "^0.0.1"
"@mapbox/vector-tile" "^2.0.4"
"@mapbox/whoots-js" "^3.1.0"
"@maplibre/geojson-vt" "^6.0.2"
"@maplibre/geojson-vt" "^6.0.3"
"@maplibre/maplibre-gl-style-spec" "^24.7.0"
"@maplibre/mlt" "^1.1.7"
"@maplibre/vt-pbf" "^4.3.0"
@@ -5721,6 +5808,11 @@ node-releases@^2.0.27:
resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz"
integrity sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==
nodemailer@^8.0.3:
version "8.0.3"
resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-8.0.3.tgz#6c5c10d3e70b8ca1b311646c4d03e1b206ef168c"
integrity sha512-JQNBqvK+bj3NMhUFR3wmCl3SYcOeMotDiwDBvIoCuQdF0PvlIY0BH+FJ2CG7u4cXKPChplE78oowlH/Otsc4ZQ==
nodemon@^3.1.14:
version "3.1.14"
resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-3.1.14.tgz#8487ca379c515301d221ec007f27f24ecafa2b51"
@@ -6337,10 +6429,10 @@ punycode@^2.1.0:
resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz"
integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==
puppeteer-core@24.39.1:
version "24.39.1"
resolved "https://registry.yarnpkg.com/puppeteer-core/-/puppeteer-core-24.39.1.tgz#7d155cc4b38b32ccb29b862e52b1f87e39704d6f"
integrity sha512-AMqQIKoEhPS6CilDzw0Gd1brLri3emkC+1N2J6ZCCuY1Cglo56M63S0jOeBZDQlemOiRd686MYVMl9ELJBzN3A==
puppeteer-core@24.40.0:
version "24.40.0"
resolved "https://registry.yarnpkg.com/puppeteer-core/-/puppeteer-core-24.40.0.tgz#1f389cd9432cb077f703ca2cb6758490cdccbc7e"
integrity sha512-MWL3XbUCfVgGR0gRsidzT6oKJT2QydPLhMITU6HoVWiiv4gkb6gJi3pcdAa8q4HwjBTbqISOWVP4aJiiyUJvag==
dependencies:
"@puppeteer/browsers" "2.13.0"
chromium-bidi "14.0.0"
@@ -6397,16 +6489,16 @@ puppeteer-extra@^3.3.6:
debug "^4.1.1"
deepmerge "^4.2.2"
puppeteer@^24.39.1:
version "24.39.1"
resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-24.39.1.tgz#5ca7db71508a35d00d4a3b23a9c117ea2022efc3"
integrity sha512-68Zc9QpcVvfxp2C+3UL88TyUogEAn5tSylXidbEuEXvhiqK1+v65zeBU5ubinAgEHMGr3dcSYqvYrGtdzsPI3w==
puppeteer@^24.40.0:
version "24.40.0"
resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-24.40.0.tgz#6df6aeee9dabf29bed3bb2be5c209d00518d4a79"
integrity sha512-IxQbDq93XHVVLWHrAkFP7F7iHvb9o0mgfsSIMlhHb+JM+JjM1V4v4MNSQfcRWJopx9dsNOr9adYv0U5fm9BJBQ==
dependencies:
"@puppeteer/browsers" "2.13.0"
chromium-bidi "14.0.0"
cosmiconfig "^9.0.0"
devtools-protocol "0.0.1581282"
puppeteer-core "24.39.1"
puppeteer-core "24.40.0"
typed-query-selector "^2.12.1"
qs@^6.14.0:
@@ -6800,6 +6892,30 @@ robust-predicates@^3.0.2:
resolved "https://registry.yarnpkg.com/robust-predicates/-/robust-predicates-3.0.2.tgz#d5b28528c4824d20fc48df1928d41d9efa1ad771"
integrity sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==
rolldown@1.0.0-rc.10:
version "1.0.0-rc.10"
resolved "https://registry.yarnpkg.com/rolldown/-/rolldown-1.0.0-rc.10.tgz#41c55e52d833c52c90131973047250548e35f2bf"
integrity sha512-q7j6vvarRFmKpgJUT8HCAUljkgzEp4LAhPlJUvQhA5LA1SUL36s5QCysMutErzL3EbNOZOkoziSx9iZC4FddKA==
dependencies:
"@oxc-project/types" "=0.120.0"
"@rolldown/pluginutils" "1.0.0-rc.10"
optionalDependencies:
"@rolldown/binding-android-arm64" "1.0.0-rc.10"
"@rolldown/binding-darwin-arm64" "1.0.0-rc.10"
"@rolldown/binding-darwin-x64" "1.0.0-rc.10"
"@rolldown/binding-freebsd-x64" "1.0.0-rc.10"
"@rolldown/binding-linux-arm-gnueabihf" "1.0.0-rc.10"
"@rolldown/binding-linux-arm64-gnu" "1.0.0-rc.10"
"@rolldown/binding-linux-arm64-musl" "1.0.0-rc.10"
"@rolldown/binding-linux-ppc64-gnu" "1.0.0-rc.10"
"@rolldown/binding-linux-s390x-gnu" "1.0.0-rc.10"
"@rolldown/binding-linux-x64-gnu" "1.0.0-rc.10"
"@rolldown/binding-linux-x64-musl" "1.0.0-rc.10"
"@rolldown/binding-openharmony-arm64" "1.0.0-rc.10"
"@rolldown/binding-wasm32-wasi" "1.0.0-rc.10"
"@rolldown/binding-win32-arm64-msvc" "1.0.0-rc.10"
"@rolldown/binding-win32-x64-msvc" "1.0.0-rc.10"
rolldown@1.0.0-rc.9:
version "1.0.0-rc.9"
resolved "https://registry.yarnpkg.com/rolldown/-/rolldown-1.0.0-rc.9.tgz#5a0d3e194f2bcc7a134870b174042fcaed463689"
@@ -7764,7 +7880,20 @@ vfile@^6.0.0:
"@types/unist" "^3.0.0"
vfile-message "^4.0.0"
vite@8.0.0, "vite@^6.0.0 || ^7.0.0 || ^8.0.0-0":
vite@8.0.1:
version "8.0.1"
resolved "https://registry.yarnpkg.com/vite/-/vite-8.0.1.tgz#015cef9a747c07c0cf9cf553f37571885504e9d3"
integrity sha512-wt+Z2qIhfFt85uiyRt5LPU4oVEJBXj8hZNWKeqFG4gRG/0RaRGJ7njQCwzFVjO+v4+Ipmf5CY7VdmZRAYYBPHw==
dependencies:
lightningcss "^1.32.0"
picomatch "^4.0.3"
postcss "^8.5.8"
rolldown "1.0.0-rc.10"
tinyglobby "^0.2.15"
optionalDependencies:
fsevents "~2.3.3"
"vite@^6.0.0 || ^7.0.0 || ^8.0.0-0":
version "8.0.0"
resolved "https://registry.yarnpkg.com/vite/-/vite-8.0.0.tgz#d749f9bf5be196635982bc16ec0c6faf2b31f3a4"
integrity sha512-fPGaRNj9Zytaf8LEiBhY7Z6ijnFKdzU/+mL8EFBaKr7Vw1/FWcTBAMW0wLPJAGMPX38ZPVCVgLceWiEqeoqL2Q==