Initial commit

This commit is contained in:
2026-02-12 17:31:08 -03:00
commit a92e2f7024
10 changed files with 637 additions and 0 deletions

9
.dockerignore Normal file
View File

@@ -0,0 +1,9 @@
# Avoid sending secrets or dev tooling into the build context
# conf/config.local.php is included (no secrets; reads from ENV)
node_modules
.git
.prettierrc
.prettierignore
*.md
.env
.env.*

66
.env.example Normal file
View File

@@ -0,0 +1,66 @@
# PostfixAdmin environment variables. Copy to .env and set secrets; optional overrides below.
# For Portainer: use Stack → ENV (advanced) and paste KEY=VALUE lines, or mount .env.
# Required (no default; app will error if missing):
PFA_SETUP_PASSWORD=
PFA_DATABASE_PASSWORD=
PFA_ADMIN_SMTP_PASSWORD=
# --- Database ---
PFA_DATABASE_HOST=mail.mifi.holdings
PFA_DATABASE_USER=postfixadmin
PFA_DATABASE_NAME=postfix
PFA_DATABASE_TYPE=mysqli
# --- Encryption ---
PFA_ENCRYPT=php_crypt:BLOWFISH:13:{BLF-CRYPT}
# --- Branding and URLs ---
PFA_SITE_URL=https://postmaster.mifi.holdings
PFA_SITE_NAME=mifi Ventures Email Service
PFA_WELCOME_TEXT=Welcome to mifi Ventures Email Service — <a href="https://mail.mifi.holdings/help" target="_blank">help</a>
PFA_SHOW_HEADER_TEXT=YES
PFA_HEADER_TEXT=mifi Ventures Email Service
PFA_FOOTER_TEXT=mifi Ventures Mail
PFA_FOOTER_LINK=https://mail.mifi.holdings
# --- Language ---
PFA_DEFAULT_LANGUAGE=en
PFA_DEFAULT_CHARSET=UTF-8
# --- Features (YES/NO) ---
PFA_SPECIAL_ALIAS_CONTROL=NO
PFA_BACKUP=NO
PFA_FETCHMAIL=NO
PFA_SENDMAIL=NO
PFA_APP_PASSWORDS=YES
# --- Quotas ---
PFA_QUOTA=YES
PFA_USED_QUOTAS=YES
PFA_MAILBOXES=100
PFA_MAXQUOTA=10240
PFA_DOMAIN_QUOTA_DEFAULT=102400
# --- SMTP for admin notifications ---
PFA_ADMIN_EMAIL=noreply@mifi.holdings
PFA_ADMIN_NAME=mifi Ventures Postmaster
PFA_SMTP_SERVER=mail.mifi.holdings
PFA_SMTP_PORT=587
PFA_SMTP_TYPE=starttls
PFA_SMTP_AUTH=true
# --- Self-service and security (true/false) ---
PFA_EDIT_MAILBOX=true
PFA_EDIT_ALIAS=true
PFA_FORGOTTEN_ADMIN_PASSWORD_RESET=true
PFA_FORGOTTEN_USER_PASSWORD_RESET=true
PFA_ADMIN_2FA=true
# --- API ---
PFA_API_ENABLED=true
PFA_API_ALLOW_FROM=127.0.0.1,::1
# --- Session (seconds) ---
PFA_SESSION_TIMEOUT=1800
# Note: password_validation and default_aliases are defined in conf/config.local.php (PHP arrays).

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
.env
.env.*
!.env.example

3
.prettierignore Normal file
View File

@@ -0,0 +1,3 @@
node_modules
pnpm-lock.yaml
conf

15
.prettierrc Normal file
View File

@@ -0,0 +1,15 @@
{
"semi": false,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "none",
"overrides": [
{
"files": "*.yml",
"options": {
"tabWidth": 4,
"proseWrap": "preserve"
}
}
]
}

8
Dockerfile Normal file
View File

@@ -0,0 +1,8 @@
# Registry image for mifi PostfixAdmin stack.
# config.local.php reads all sensitive/configurable values from ENV (PFA_*); no bind mount needed.
ARG PFA_VERSION=latest
FROM postfixadmin:${PFA_VERSION}
COPY conf/config.local.php /var/www/html/config.local.php
LABEL org.opencontainers.image.source="https://git.mifi.dev/mifi-holdings/mail-postfixadmin"

109
conf/config.local.php Normal file
View File

@@ -0,0 +1,109 @@
<?php
/**
* PostfixAdmin config: sensitive values from ENV (no default), rest configurable via ENV with defaults.
* See .env.example for all variable names.
*/
$CONF['configured'] = true;
// --- Helpers: required ENV (no default) vs optional with default ---
function pfa_env(string $key, ?string $default = null): string {
$v = getenv($key);
if ($default === null) {
if ($v === false || $v === '') {
throw new \RuntimeException('Set ' . $key);
}
return $v;
}
return ($v === false || $v === '') ? $default : $v;
}
function pfa_env_bool(string $key, bool $default = true): bool {
$v = getenv($key);
if ($v === false || $v === '') {
return $default;
}
return filter_var($v, FILTER_VALIDATE_BOOLEAN);
}
// Sensitive: no default (must be set in ENV / .env)
$CONF['setup_password'] = pfa_env('PFA_SETUP_PASSWORD');
$CONF['database_password'] = pfa_env('PFA_DATABASE_PASSWORD');
$CONF['admin_smtp_password'] = pfa_env('PFA_ADMIN_SMTP_PASSWORD');
// Database configuration
$CONF['database_host'] = pfa_env('PFA_DATABASE_HOST', 'mail.mifi.holdings');
$CONF['database_user'] = pfa_env('PFA_DATABASE_USER', 'postfixadmin');
$CONF['database_name'] = pfa_env('PFA_DATABASE_NAME', 'postfix');
$CONF['database_type'] = pfa_env('PFA_DATABASE_TYPE', 'mysqli');
// Password encryption
$CONF['encrypt'] = pfa_env('PFA_ENCRYPT', 'php_crypt:BLOWFISH:13:{BLF-CRYPT}');
// Branding and URLs
$CONF['site_url'] = pfa_env('PFA_SITE_URL', 'https://postmaster.mifi.holdings');
$CONF['site_name'] = pfa_env('PFA_SITE_NAME', 'mifi Ventures Email Service');
// Language & charset
$CONF['default_language'] = pfa_env('PFA_DEFAULT_LANGUAGE', 'en');
$CONF['default_charset'] = pfa_env('PFA_DEFAULT_CHARSET', 'UTF-8');
// Password validation (array left in file; override via config.inc.php if needed)
$CONF['password_validation'] = array(
'/.{5}/' => 'password_too_short 5',
'/([a-zA-Z].*){3}/' => 'password_no_characters 3',
'/([0-9].*){1}/' => 'password_no_digits 2',
'/([!\".,*&^%$£)(_+=\-`\'#@~\[\]\\<>\/].*){1,}/' => 'password_no_special 1',
);
// Features
$CONF['special_alias_control'] = pfa_env('PFA_SPECIAL_ALIAS_CONTROL', 'NO');
$CONF['backup'] = pfa_env('PFA_BACKUP', 'NO');
$CONF['fetchmail'] = pfa_env('PFA_FETCHMAIL', 'NO');
$CONF['sendmail'] = pfa_env('PFA_SENDMAIL', 'NO');
$CONF['app_passwords'] = pfa_env('PFA_APP_PASSWORDS', 'YES');
// Welcome and footer text (branding + docs)
$CONF['welcome_text'] = pfa_env('PFA_WELCOME_TEXT', 'Welcome to mifi Ventures Email Service — <a href="https://mail.mifi.holdings/help" target="_blank">help</a>');
$CONF['show_header_text'] = pfa_env('PFA_SHOW_HEADER_TEXT', 'YES');
$CONF['header_text'] = pfa_env('PFA_HEADER_TEXT', 'mifi Ventures Email Service');
$CONF['footer_text'] = pfa_env('PFA_FOOTER_TEXT', 'mifi Ventures Mail');
$CONF['footer_link'] = pfa_env('PFA_FOOTER_LINK', 'https://mail.mifi.holdings');
// Default aliases (array; edit in file or extend via config.inc.php)
$CONF['default_aliases'] = array(
'alerts' => 'alerts@mifi.holdings',
'abuse' => 'abuse@mifi.holdings',
'hostmaster' => 'hostmaster@mifi.holdings',
'postmaster' => 'postmaster@mifi.holdings',
'webmaster' => 'webmaster@mifi.holdings'
);
// Quota and mailbox limits
$CONF['quota'] = pfa_env('PFA_QUOTA', 'YES');
$CONF['used_quotas'] = pfa_env('PFA_USED_QUOTAS', 'YES');
$CONF['mailboxes'] = pfa_env('PFA_MAILBOXES', '100');
$CONF['maxquota'] = pfa_env('PFA_MAXQUOTA', '10240');
$CONF['domain_quota_default'] = pfa_env('PFA_DOMAIN_QUOTA_DEFAULT', '102400');
// SMTP settings for admin notifications
$CONF['admin_email'] = pfa_env('PFA_ADMIN_EMAIL', 'noreply@mifi.holdings');
$CONF['admin_name'] = pfa_env('PFA_ADMIN_NAME', 'mifi Ventures Postmaster');
$CONF['smtp_server'] = pfa_env('PFA_SMTP_SERVER', 'mail.mifi.holdings');
$CONF['smtp_port'] = pfa_env('PFA_SMTP_PORT', '587');
$CONF['smtp_type'] = pfa_env('PFA_SMTP_TYPE', 'starttls');
$CONF['smtp_auth'] = pfa_env_bool('PFA_SMTP_AUTH', true);
// Self-service and editing
$CONF['edit_mailbox'] = pfa_env_bool('PFA_EDIT_MAILBOX', true);
$CONF['edit_alias'] = pfa_env_bool('PFA_EDIT_ALIAS', true);
$CONF['forgotten_admin_password_reset'] = pfa_env_bool('PFA_FORGOTTEN_ADMIN_PASSWORD_RESET', true);
$CONF['forgotten_user_password_reset'] = pfa_env_bool('PFA_FORGOTTEN_USER_PASSWORD_RESET', true);
$CONF['admin_2fa'] = pfa_env_bool('PFA_ADMIN_2FA', true);
// API (comma-separated list for api_allow_from)
$CONF['api_enabled'] = pfa_env_bool('PFA_API_ENABLED', true);
$CONF['api_allow_from'] = array_map('trim', explode(',', pfa_env('PFA_API_ALLOW_FROM', '127.0.0.1,::1')));
// Session timeout (seconds)
$CONF['session_timeout'] = (int) pfa_env('PFA_SESSION_TIMEOUT', '1800');

26
docker-compose.yml Normal file
View File

@@ -0,0 +1,26 @@
services:
postfixadmin:
image: git.mifi.dev/mifi-holdings/mail-postfixadmin:latest
container_name: mifi-mail-postfixadmin
# ENV: set PFA_* in Portainer stack → ENV (advanced); paste from .env or .env.example
healthcheck:
test: curl --fail http://localhost || exit 1
retries: 5
start_period: 30s
restart: unless-stopped
networks:
- traefik
volumes:
- /var/run/mysqld/mysqld.sock:/var/run/mysqld/mysqld.sock:ro
labels:
- 'traefik.enable=true'
- 'traefik.docker.network=traefik'
- 'traefik.http.routers.postfixadmin.rule=Host(`postmaster.mifi.holdings`)'
- 'traefik.http.routers.postfixadmin.middlewares=gzip@file,security-medium@file'
- 'traefik.http.routers.postfixadmin.entrypoints=websecure'
- 'traefik.http.routers.postfixadmin.tls=true'
- 'traefik.http.routers.postfixadmin.tls.certresolver=letsencrypt'
networks:
traefik:
external: true

17
package.json Normal file
View File

@@ -0,0 +1,17 @@
{
"name": "mail-postfixadmin",
"version": "1.0.0",
"private": true,
"packageManager": "pnpm@10.29.3+sha512.498e1fb4cca5aa06c1dcf2611e6fafc50972ffe7189998c409e90de74566444298ffe43e6cd2acdc775ba1aa7cc5e092a8b7054c811ba8c5770f84693d33d2dc",
"scripts": {
"format": "prettier --write .",
"format:check": "prettier --check .",
"lint": "yamllint .woodpecker/ci.yml .woodpecker/build.yml .woodpecker/deploy.yml docker-compose.yml",
"docker:build": "docker build --platform linux/amd64 -t git.mifi.dev/mifi-holdings/mail-postfixadmin:latest .",
"docker:push": "docker push git.mifi.dev/mifi-holdings/mail-postfixadmin:latest"
},
"devDependencies": {
"prettier": "^3.4.2",
"yaml-lint": "^1.7.0"
}
}

381
pnpm-lock.yaml generated Normal file
View File

@@ -0,0 +1,381 @@
lockfileVersion: '9.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
importers:
.:
devDependencies:
prettier:
specifier: ^3.4.2
version: 3.8.1
yaml-lint:
specifier: ^1.7.0
version: 1.7.0
packages:
'@nodelib/fs.scandir@2.1.5':
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
'@nodelib/fs.stat@2.0.5':
resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
engines: {node: '>= 8'}
'@nodelib/fs.walk@1.2.8':
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
engines: {node: '>= 8'}
ansi-regex@5.0.1:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
ansi-styles@4.3.0:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
array-union@2.1.0:
resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
engines: {node: '>=8'}
async@3.2.6:
resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==}
braces@3.0.3:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
engines: {node: '>=8'}
cliui@7.0.4:
resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==}
color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
consola@2.15.3:
resolution: {integrity: sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==}
dir-glob@3.0.1:
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
engines: {node: '>=8'}
emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
escalade@3.2.0:
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
engines: {node: '>=6'}
fast-glob@3.3.3:
resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==}
engines: {node: '>=8.6.0'}
fastq@1.20.1:
resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==}
fill-range@7.1.1:
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
engines: {node: '>=8'}
get-caller-file@2.0.5:
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
engines: {node: 6.* || 8.* || >= 10.*}
glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
globby@11.1.0:
resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
engines: {node: '>=10'}
ignore@5.3.2:
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
engines: {node: '>= 4'}
ini@2.0.0:
resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==}
engines: {node: '>=10'}
is-extglob@2.1.1:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
is-fullwidth-code-point@3.0.0:
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
engines: {node: '>=8'}
is-glob@4.0.3:
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
engines: {node: '>=0.10.0'}
is-number@7.0.0:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
js-yaml@4.1.1:
resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
hasBin: true
merge2@1.4.1:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'}
micromatch@4.0.8:
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
engines: {node: '>=8.6'}
nconf@0.12.1:
resolution: {integrity: sha512-p2cfF+B3XXacQdswUYWZ0w6Vld0832A/tuqjLBu3H1sfUcby4N2oVbGhyuCkZv+t3iY3aiFEj7gZGqax9Q2c1w==}
engines: {node: '>= 0.4.0'}
path-type@4.0.0:
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
engines: {node: '>=8'}
picomatch@2.3.1:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'}
prettier@3.8.1:
resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==}
engines: {node: '>=14'}
hasBin: true
queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
require-directory@2.1.1:
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
engines: {node: '>=0.10.0'}
reusify@1.1.0:
resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
run-parallel@1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
secure-keys@1.0.0:
resolution: {integrity: sha512-nZi59hW3Sl5P3+wOO89eHBAAGwmCPd2aE1+dLZV5MO+ItQctIvAqihzaAXIQhvtH4KJPxM080HsnqltR2y8cWg==}
slash@3.0.0:
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
engines: {node: '>=8'}
string-width@4.2.3:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
engines: {node: '>=8'}
strip-ansi@6.0.1:
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
engines: {node: '>=8'}
to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
wrap-ansi@7.0.0:
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
engines: {node: '>=10'}
y18n@5.0.8:
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
engines: {node: '>=10'}
yaml-lint@1.7.0:
resolution: {integrity: sha512-zeBC/kskKQo4zuoGQ+IYjw6C9a/YILr2SXoEZA9jM0COrSwvwVbfTiFegT8qYBSBgOwLMWGL8sY137tOmFXGnQ==}
hasBin: true
yargs-parser@20.2.9:
resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==}
engines: {node: '>=10'}
yargs@16.2.0:
resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==}
engines: {node: '>=10'}
snapshots:
'@nodelib/fs.scandir@2.1.5':
dependencies:
'@nodelib/fs.stat': 2.0.5
run-parallel: 1.2.0
'@nodelib/fs.stat@2.0.5': {}
'@nodelib/fs.walk@1.2.8':
dependencies:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.20.1
ansi-regex@5.0.1: {}
ansi-styles@4.3.0:
dependencies:
color-convert: 2.0.1
argparse@2.0.1: {}
array-union@2.1.0: {}
async@3.2.6: {}
braces@3.0.3:
dependencies:
fill-range: 7.1.1
cliui@7.0.4:
dependencies:
string-width: 4.2.3
strip-ansi: 6.0.1
wrap-ansi: 7.0.0
color-convert@2.0.1:
dependencies:
color-name: 1.1.4
color-name@1.1.4: {}
consola@2.15.3: {}
dir-glob@3.0.1:
dependencies:
path-type: 4.0.0
emoji-regex@8.0.0: {}
escalade@3.2.0: {}
fast-glob@3.3.3:
dependencies:
'@nodelib/fs.stat': 2.0.5
'@nodelib/fs.walk': 1.2.8
glob-parent: 5.1.2
merge2: 1.4.1
micromatch: 4.0.8
fastq@1.20.1:
dependencies:
reusify: 1.1.0
fill-range@7.1.1:
dependencies:
to-regex-range: 5.0.1
get-caller-file@2.0.5: {}
glob-parent@5.1.2:
dependencies:
is-glob: 4.0.3
globby@11.1.0:
dependencies:
array-union: 2.1.0
dir-glob: 3.0.1
fast-glob: 3.3.3
ignore: 5.3.2
merge2: 1.4.1
slash: 3.0.0
ignore@5.3.2: {}
ini@2.0.0: {}
is-extglob@2.1.1: {}
is-fullwidth-code-point@3.0.0: {}
is-glob@4.0.3:
dependencies:
is-extglob: 2.1.1
is-number@7.0.0: {}
js-yaml@4.1.1:
dependencies:
argparse: 2.0.1
merge2@1.4.1: {}
micromatch@4.0.8:
dependencies:
braces: 3.0.3
picomatch: 2.3.1
nconf@0.12.1:
dependencies:
async: 3.2.6
ini: 2.0.0
secure-keys: 1.0.0
yargs: 16.2.0
path-type@4.0.0: {}
picomatch@2.3.1: {}
prettier@3.8.1: {}
queue-microtask@1.2.3: {}
require-directory@2.1.1: {}
reusify@1.1.0: {}
run-parallel@1.2.0:
dependencies:
queue-microtask: 1.2.3
secure-keys@1.0.0: {}
slash@3.0.0: {}
string-width@4.2.3:
dependencies:
emoji-regex: 8.0.0
is-fullwidth-code-point: 3.0.0
strip-ansi: 6.0.1
strip-ansi@6.0.1:
dependencies:
ansi-regex: 5.0.1
to-regex-range@5.0.1:
dependencies:
is-number: 7.0.0
wrap-ansi@7.0.0:
dependencies:
ansi-styles: 4.3.0
string-width: 4.2.3
strip-ansi: 6.0.1
y18n@5.0.8: {}
yaml-lint@1.7.0:
dependencies:
consola: 2.15.3
globby: 11.1.0
js-yaml: 4.1.1
nconf: 0.12.1
yargs-parser@20.2.9: {}
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