Toggle navigation
Toggle navigation
This project
Loading...
Sign in
卢阳
/
front_backend_zImage
Go to a project
Toggle navigation
Projects
Groups
Snippets
Help
Toggle navigation pinning
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Authored by
ly0303521
2026-02-06 14:38:45 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
63e61bf2671be8ee3fb3dc4138688e83ceb024a8
63e61bf2
1 parent
1f58c4e1
添加IP过滤策略
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
815 additions
and
10 deletions
backend/main.py
ecosystem.config.js
frontend_server.py
middleware.py
start_all.sh
z-image-generator/index.css
z-image-generator/package-lock.json
z-image-generator/package.json
z-image-generator/postcss.config.js
backend/main.py
View file @
63e61bf
...
...
@@ -16,6 +16,16 @@ from pydantic import BaseModel, Field, ConfigDict
import
logging
from
PIL
import
Image
import
io
import
sys
# Add parent directory to path to import middleware
sys
.
path
.
append
(
str
(
Path
(
__file__
)
.
parent
.
parent
))
try
:
from
middleware
import
IPFilterMiddleware
except
ImportError
:
# Fallback/Dummy if not found (should be found)
IPFilterMiddleware
=
None
# --- Constants ---
logger
=
logging
.
getLogger
(
"uvicorn.error"
)
...
...
@@ -313,6 +323,11 @@ usage_store = UsageStore(USAGE_PATH)
# --- App Setup ---
app
=
FastAPI
(
title
=
"Z-Image Proxy"
,
version
=
"1.0.0"
)
# IP Filter Middleware (Add BEFORE CORS to block early)
if
IPFilterMiddleware
:
app
.
add_middleware
(
IPFilterMiddleware
)
from
fastapi.staticfiles
import
StaticFiles
# Mount public directory to serve thumbnails and frontend config
app
.
mount
(
"/thumbnails"
,
StaticFiles
(
directory
=
str
(
Path
(
__file__
)
.
parent
.
parent
/
"public"
/
"thumbnails"
)),
name
=
"thumbnails"
)
...
...
ecosystem.config.js
View file @
63e61bf
...
...
@@ -15,13 +15,15 @@ module.exports = {
},
{
name
:
process
.
env
.
FRONTEND_NAME
||
"z-image-frontend"
,
script
:
"serve"
,
script
:
"./venv/bin/python"
,
args
:
"frontend_server.py"
,
cwd
:
__dirname
,
interpreter
:
"none"
,
autorestart
:
true
,
watch
:
false
,
env
:
{
// Use LOCAL_FRONTEND_PORT from environment, default to 7001
PM2_SERVE_PATH
:
path
.
join
(
__dirname
,
'z-image-generator/dist'
),
PM2_SERVE_PORT
:
process
.
env
.
LOCAL_FRONTEND_PORT
||
7001
,
PM2_SERVE_SPA
:
'true'
,
PM2_SERVE_HOMEPAGE
:
'/index.html'
LOCAL_FRONTEND_PORT
:
process
.
env
.
LOCAL_FRONTEND_PORT
||
7001
,
ENABLE_IP_FILTER
:
process
.
env
.
ENABLE_IP_FILTER
}
}
]
...
...
frontend_server.py
0 → 100644
View file @
63e61bf
import
os
from
fastapi
import
FastAPI
from
fastapi.staticfiles
import
StaticFiles
from
fastapi.responses
import
FileResponse
from
middleware
import
IPFilterMiddleware
app
=
FastAPI
()
# Add IP Filter Middleware
app
.
add_middleware
(
IPFilterMiddleware
)
# Frontend Dist Path
DIST_DIR
=
os
.
path
.
join
(
os
.
path
.
dirname
(
__file__
),
"z-image-generator"
,
"dist"
)
# Ensure dist exists
if
not
os
.
path
.
exists
(
DIST_DIR
):
os
.
makedirs
(
DIST_DIR
,
exist_ok
=
True
)
# Create a dummy index.html if not exists for testing
with
open
(
os
.
path
.
join
(
DIST_DIR
,
"index.html"
),
"w"
)
as
f
:
f
.
write
(
"<h1>Frontend Build Not Found</h1>"
)
# Serve Static Files
# We mount root to serve static files, BUT we need SPA fallback.
# Solution: Mount specific assets folder, and use a catch-all for index.html
# 1. Mount /assets if it exists in dist
assets_path
=
os
.
path
.
join
(
DIST_DIR
,
"assets"
)
if
os
.
path
.
exists
(
assets_path
):
app
.
mount
(
"/assets"
,
StaticFiles
(
directory
=
assets_path
),
name
=
"assets"
)
# 2. Serve other static files (like favicon, etc) if needed?
# For simplicity, we just use a catch-all route to serve index.html or the file if it exists
@app.get
(
"/{full_path:path}"
)
async
def
serve_spa
(
full_path
:
str
):
# Check if file exists in dist
file_path
=
os
.
path
.
join
(
DIST_DIR
,
full_path
)
if
os
.
path
.
exists
(
file_path
)
and
os
.
path
.
isfile
(
file_path
):
return
FileResponse
(
file_path
)
# Fallback to index.html for SPA
# Disable cache for index.html to ensure updates are seen immediately
response
=
FileResponse
(
os
.
path
.
join
(
DIST_DIR
,
"index.html"
))
response
.
headers
[
"Cache-Control"
]
=
"no-cache, no-store, must-revalidate"
response
.
headers
[
"Pragma"
]
=
"no-cache"
response
.
headers
[
"Expires"
]
=
"0"
return
response
if
__name__
==
"__main__"
:
import
uvicorn
# Read port from env or default
port
=
int
(
os
.
getenv
(
"LOCAL_FRONTEND_PORT"
,
"7001"
))
uvicorn
.
run
(
app
,
host
=
"0.0.0.0"
,
port
=
port
)
...
...
middleware.py
0 → 100644
View file @
63e61bf
import
os
import
time
import
logging
from
logging.handlers
import
RotatingFileHandler
from
datetime
import
datetime
from
typing
import
Optional
,
Tuple
from
fastapi
import
Request
,
HTTPException
,
Response
from
starlette.middleware.base
import
BaseHTTPMiddleware
from
starlette.responses
import
JSONResponse
,
PlainTextResponse
import
httpx
# Configuration
ENABLE_IP_FILTER
=
os
.
getenv
(
"ENABLE_IP_FILTER"
,
"false"
)
.
lower
()
==
"true"
LOG_FILE
=
os
.
path
.
join
(
os
.
path
.
expanduser
(
"~"
),
".pm2"
,
"logs"
,
"access_monitor.log"
)
# Setup Logger
logger
=
logging
.
getLogger
(
"access_monitor"
)
logger
.
setLevel
(
logging
.
INFO
)
formatter
=
logging
.
Formatter
(
'
%(message)
s'
)
# Use RotatingFileHandler instead of FileHandler
# maxBytes=10MB, backupCount=10 (Max storage ~100MB)
file_handler
=
RotatingFileHandler
(
LOG_FILE
,
maxBytes
=
10
*
1024
*
1024
,
backupCount
=
10
,
encoding
=
'utf-8'
)
file_handler
.
setFormatter
(
formatter
)
logger
.
addHandler
(
file_handler
)
# IP Cache: {ip: {"is_cn": bool, "location": str, "timestamp": float}}
IP_CACHE
=
{}
async
def
get_ip_info
(
ip
:
str
)
->
Tuple
[
bool
,
str
]:
"""
Check if IP is from China and get location.
Returns (is_cn, location_string)
"""
# Localhost / Private IP checks
if
ip
==
"127.0.0.1"
or
ip
==
"::1"
or
ip
.
startswith
(
"192.168."
)
or
ip
.
startswith
(
"10."
):
return
True
,
"Local Network"
# Check Cache
if
ip
in
IP_CACHE
:
# Cache for 24 hours
if
time
.
time
()
-
IP_CACHE
[
ip
][
"timestamp"
]
<
86400
:
return
IP_CACHE
[
ip
][
"is_cn"
],
IP_CACHE
[
ip
][
"location"
]
# Query API
# Using ip-api.com (free, non-commercial use, 45 req/min)
# Lang=zh-CN for Chinese output
url
=
f
"http://ip-api.com/json/{ip}?lang=zh-CN&fields=status,countryCode,country,regionName,city"
try
:
async
with
httpx
.
AsyncClient
(
timeout
=
3.0
)
as
client
:
resp
=
await
client
.
get
(
url
)
data
=
resp
.
json
()
if
data
.
get
(
"status"
)
==
"success"
:
is_cn
=
data
.
get
(
"countryCode"
)
==
"CN"
location
=
f
"{data.get('country')}-{data.get('regionName')}-{data.get('city')}"
# Update Cache
IP_CACHE
[
ip
]
=
{
"is_cn"
:
is_cn
,
"location"
:
location
,
"timestamp"
:
time
.
time
()
}
return
is_cn
,
location
else
:
# API failed or private IP
return
True
,
"Unknown/Private"
except
Exception
as
e
:
print
(
f
"IP Lookup failed for {ip}: {e}"
)
# Fail open (allow access) if API fails
return
True
,
"Lookup Failed"
class
IPFilterMiddleware
(
BaseHTTPMiddleware
):
async
def
dispatch
(
self
,
request
:
Request
,
call_next
):
start_time
=
time
.
time
()
# Get Client IP
# X-Forwarded-For is preferred if behind proxy (like Nginx), but here we might be direct or behind pm2
forwarded
=
request
.
headers
.
get
(
"X-Forwarded-For"
)
if
forwarded
:
client_ip
=
forwarded
.
split
(
","
)[
0
]
else
:
client_ip
=
request
.
client
.
host
if
request
.
client
else
"unknown"
# Determine Port (Local port server is listening on)
server_port
=
request
.
scope
.
get
(
"server"
,
(
""
,
"unknown"
))[
1
]
# IP Lookup
is_allowed
=
True
location
=
"Unknown"
# Optimize: Skip static assets logs to reduce noise?
# Requirement says "Add record access IP log", implies all or relevant ones.
# We will log everything for now or filter ext.
is_cn
,
location
=
await
get_ip_info
(
client_ip
)
if
ENABLE_IP_FILTER
and
not
is_cn
:
is_allowed
=
False
# Explicit check for HK/TW/MO if they somehow pass as CN (though API shouldn't do that)
# or if user wants double security.
# Based on ip-api.com, 'HK', 'TW', 'MO' are country codes, not 'CN'.
# So 'is_cn' check above is sufficient.
# DEBUG: Log if we are blocking to ensure config works
if
not
is_allowed
:
print
(
f
"[BLOCK] Blocked {client_ip} ({location})"
)
# Access Time
access_time
=
datetime
.
now
()
.
strftime
(
"
%
Y-
%
m-
%
d
%
H:
%
M:
%
S"
)
# Log Format: IP | Location | Time | Port | Path | Allowed
log_msg
=
f
"{client_ip} | {location} | {access_time} | {server_port} | {request.url.path} | {'ALLOWED' if is_allowed else 'BLOCKED'}"
logger
.
info
(
log_msg
)
if
not
is_allowed
:
return
PlainTextResponse
(
"Access Denied: Mainland China IP Required"
,
status_code
=
403
)
response
=
await
call_next
(
request
)
return
response
...
...
start_all.sh
View file @
63e61bf
...
...
@@ -10,6 +10,9 @@ else
exit
1
fi
# IP Filter Switch (Default to true for security)
export
ENABLE_IP_FILTER
=
"
${
ENABLE_IP_FILTER
:-
true
}
"
# Bypass proxy for local connections
export
no_proxy
=
"localhost,127.0.0.1,0.0.0.0,::1"
export
NO_PROXY
=
"localhost,127.0.0.1,0.0.0.0,::1"
...
...
z-image-generator/index.css
View file @
63e61bf
@tailwind
base
;
@tailwind
components
;
@tailwind
utilities
;
@import
"tailwindcss"
;
/* Hide scrollbar for Chrome, Safari and Opera */
.no-scrollbar
::-webkit-scrollbar
{
...
...
z-image-generator/package-lock.json
View file @
63e61bf
...
...
@@ -13,6 +13,7 @@
"react-dom"
:
"^19.2.3"
},
"devDependencies"
:
{
"@tailwindcss/postcss"
:
"^4.1.18"
,
"@types/node"
:
"^22.14.0"
,
"@vitejs/plugin-react"
:
"^5.0.0"
,
"autoprefixer"
:
"^10.4.24"
,
...
...
@@ -22,6 +23,19 @@
"vite"
:
"^6.2.0"
}
},
"node_modules/@alloc/quick-lru"
:
{
"version"
:
"5.2.0"
,
"resolved"
:
"https://repo.huaweicloud.com/repository/npm/@alloc/quick-lru/-/quick-lru-5.2.0.tgz"
,
"integrity"
:
"sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="
,
"dev"
:
true
,
"license"
:
"MIT"
,
"engines"
:
{
"node"
:
">=10"
},
"funding"
:
{
"url"
:
"https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@babel/code-frame"
:
{
"version"
:
"7.27.1"
,
"resolved"
:
"https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz"
,
...
...
@@ -1111,6 +1125,277 @@
"win32"
]
},
"node_modules/@tailwindcss/node"
:
{
"version"
:
"4.1.18"
,
"resolved"
:
"https://repo.huaweicloud.com/repository/npm/@tailwindcss/node/-/node-4.1.18.tgz"
,
"integrity"
:
"sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ=="
,
"dev"
:
true
,
"license"
:
"MIT"
,
"dependencies"
:
{
"@jridgewell/remapping"
:
"^2.3.4"
,
"enhanced-resolve"
:
"^5.18.3"
,
"jiti"
:
"^2.6.1"
,
"lightningcss"
:
"1.30.2"
,
"magic-string"
:
"^0.30.21"
,
"source-map-js"
:
"^1.2.1"
,
"tailwindcss"
:
"4.1.18"
}
},
"node_modules/@tailwindcss/oxide"
:
{
"version"
:
"4.1.18"
,
"resolved"
:
"https://repo.huaweicloud.com/repository/npm/@tailwindcss/oxide/-/oxide-4.1.18.tgz"
,
"integrity"
:
"sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A=="
,
"dev"
:
true
,
"license"
:
"MIT"
,
"engines"
:
{
"node"
:
">= 10"
},
"optionalDependencies"
:
{
"@tailwindcss/oxide-android-arm64"
:
"4.1.18"
,
"@tailwindcss/oxide-darwin-arm64"
:
"4.1.18"
,
"@tailwindcss/oxide-darwin-x64"
:
"4.1.18"
,
"@tailwindcss/oxide-freebsd-x64"
:
"4.1.18"
,
"@tailwindcss/oxide-linux-arm-gnueabihf"
:
"4.1.18"
,
"@tailwindcss/oxide-linux-arm64-gnu"
:
"4.1.18"
,
"@tailwindcss/oxide-linux-arm64-musl"
:
"4.1.18"
,
"@tailwindcss/oxide-linux-x64-gnu"
:
"4.1.18"
,
"@tailwindcss/oxide-linux-x64-musl"
:
"4.1.18"
,
"@tailwindcss/oxide-wasm32-wasi"
:
"4.1.18"
,
"@tailwindcss/oxide-win32-arm64-msvc"
:
"4.1.18"
,
"@tailwindcss/oxide-win32-x64-msvc"
:
"4.1.18"
}
},
"node_modules/@tailwindcss/oxide-android-arm64"
:
{
"version"
:
"4.1.18"
,
"resolved"
:
"https://repo.huaweicloud.com/repository/npm/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.18.tgz"
,
"integrity"
:
"sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q=="
,
"cpu"
:
[
"arm64"
],
"dev"
:
true
,
"license"
:
"MIT"
,
"optional"
:
true
,
"os"
:
[
"android"
],
"engines"
:
{
"node"
:
">= 10"
}
},
"node_modules/@tailwindcss/oxide-darwin-arm64"
:
{
"version"
:
"4.1.18"
,
"resolved"
:
"https://repo.huaweicloud.com/repository/npm/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.18.tgz"
,
"integrity"
:
"sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A=="
,
"cpu"
:
[
"arm64"
],
"dev"
:
true
,
"license"
:
"MIT"
,
"optional"
:
true
,
"os"
:
[
"darwin"
],
"engines"
:
{
"node"
:
">= 10"
}
},
"node_modules/@tailwindcss/oxide-darwin-x64"
:
{
"version"
:
"4.1.18"
,
"resolved"
:
"https://repo.huaweicloud.com/repository/npm/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.18.tgz"
,
"integrity"
:
"sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw=="
,
"cpu"
:
[
"x64"
],
"dev"
:
true
,
"license"
:
"MIT"
,
"optional"
:
true
,
"os"
:
[
"darwin"
],
"engines"
:
{
"node"
:
">= 10"
}
},
"node_modules/@tailwindcss/oxide-freebsd-x64"
:
{
"version"
:
"4.1.18"
,
"resolved"
:
"https://repo.huaweicloud.com/repository/npm/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.18.tgz"
,
"integrity"
:
"sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA=="
,
"cpu"
:
[
"x64"
],
"dev"
:
true
,
"license"
:
"MIT"
,
"optional"
:
true
,
"os"
:
[
"freebsd"
],
"engines"
:
{
"node"
:
">= 10"
}
},
"node_modules/@tailwindcss/oxide-linux-arm-gnueabihf"
:
{
"version"
:
"4.1.18"
,
"resolved"
:
"https://repo.huaweicloud.com/repository/npm/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.18.tgz"
,
"integrity"
:
"sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA=="
,
"cpu"
:
[
"arm"
],
"dev"
:
true
,
"license"
:
"MIT"
,
"optional"
:
true
,
"os"
:
[
"linux"
],
"engines"
:
{
"node"
:
">= 10"
}
},
"node_modules/@tailwindcss/oxide-linux-arm64-gnu"
:
{
"version"
:
"4.1.18"
,
"resolved"
:
"https://repo.huaweicloud.com/repository/npm/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.18.tgz"
,
"integrity"
:
"sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw=="
,
"cpu"
:
[
"arm64"
],
"dev"
:
true
,
"license"
:
"MIT"
,
"optional"
:
true
,
"os"
:
[
"linux"
],
"engines"
:
{
"node"
:
">= 10"
}
},
"node_modules/@tailwindcss/oxide-linux-arm64-musl"
:
{
"version"
:
"4.1.18"
,
"resolved"
:
"https://repo.huaweicloud.com/repository/npm/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.18.tgz"
,
"integrity"
:
"sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg=="
,
"cpu"
:
[
"arm64"
],
"dev"
:
true
,
"license"
:
"MIT"
,
"optional"
:
true
,
"os"
:
[
"linux"
],
"engines"
:
{
"node"
:
">= 10"
}
},
"node_modules/@tailwindcss/oxide-linux-x64-gnu"
:
{
"version"
:
"4.1.18"
,
"resolved"
:
"https://repo.huaweicloud.com/repository/npm/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.18.tgz"
,
"integrity"
:
"sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g=="
,
"cpu"
:
[
"x64"
],
"dev"
:
true
,
"license"
:
"MIT"
,
"optional"
:
true
,
"os"
:
[
"linux"
],
"engines"
:
{
"node"
:
">= 10"
}
},
"node_modules/@tailwindcss/oxide-linux-x64-musl"
:
{
"version"
:
"4.1.18"
,
"resolved"
:
"https://repo.huaweicloud.com/repository/npm/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.18.tgz"
,
"integrity"
:
"sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ=="
,
"cpu"
:
[
"x64"
],
"dev"
:
true
,
"license"
:
"MIT"
,
"optional"
:
true
,
"os"
:
[
"linux"
],
"engines"
:
{
"node"
:
">= 10"
}
},
"node_modules/@tailwindcss/oxide-wasm32-wasi"
:
{
"version"
:
"4.1.18"
,
"resolved"
:
"https://repo.huaweicloud.com/repository/npm/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.18.tgz"
,
"integrity"
:
"sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA=="
,
"bundleDependencies"
:
[
"@napi-rs/wasm-runtime"
,
"@emnapi/core"
,
"@emnapi/runtime"
,
"@tybys/wasm-util"
,
"@emnapi/wasi-threads"
,
"tslib"
],
"cpu"
:
[
"wasm32"
],
"dev"
:
true
,
"license"
:
"MIT"
,
"optional"
:
true
,
"dependencies"
:
{
"@emnapi/core"
:
"^1.7.1"
,
"@emnapi/runtime"
:
"^1.7.1"
,
"@emnapi/wasi-threads"
:
"^1.1.0"
,
"@napi-rs/wasm-runtime"
:
"^1.1.0"
,
"@tybys/wasm-util"
:
"^0.10.1"
,
"tslib"
:
"^2.4.0"
},
"engines"
:
{
"node"
:
">=14.0.0"
}
},
"node_modules/@tailwindcss/oxide-win32-arm64-msvc"
:
{
"version"
:
"4.1.18"
,
"resolved"
:
"https://repo.huaweicloud.com/repository/npm/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.18.tgz"
,
"integrity"
:
"sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA=="
,
"cpu"
:
[
"arm64"
],
"dev"
:
true
,
"license"
:
"MIT"
,
"optional"
:
true
,
"os"
:
[
"win32"
],
"engines"
:
{
"node"
:
">= 10"
}
},
"node_modules/@tailwindcss/oxide-win32-x64-msvc"
:
{
"version"
:
"4.1.18"
,
"resolved"
:
"https://repo.huaweicloud.com/repository/npm/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.18.tgz"
,
"integrity"
:
"sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q=="
,
"cpu"
:
[
"x64"
],
"dev"
:
true
,
"license"
:
"MIT"
,
"optional"
:
true
,
"os"
:
[
"win32"
],
"engines"
:
{
"node"
:
">= 10"
}
},
"node_modules/@tailwindcss/postcss"
:
{
"version"
:
"4.1.18"
,
"resolved"
:
"https://repo.huaweicloud.com/repository/npm/@tailwindcss/postcss/-/postcss-4.1.18.tgz"
,
"integrity"
:
"sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g=="
,
"dev"
:
true
,
"license"
:
"MIT"
,
"dependencies"
:
{
"@alloc/quick-lru"
:
"^5.2.0"
,
"@tailwindcss/node"
:
"4.1.18"
,
"@tailwindcss/oxide"
:
"4.1.18"
,
"postcss"
:
"^8.4.41"
,
"tailwindcss"
:
"4.1.18"
}
},
"node_modules/@types/babel__core"
:
{
"version"
:
"7.20.5"
,
"resolved"
:
"https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz"
,
...
...
@@ -1321,6 +1606,16 @@
}
}
},
"node_modules/detect-libc"
:
{
"version"
:
"2.1.2"
,
"resolved"
:
"https://repo.huaweicloud.com/repository/npm/detect-libc/-/detect-libc-2.1.2.tgz"
,
"integrity"
:
"sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="
,
"dev"
:
true
,
"license"
:
"Apache-2.0"
,
"engines"
:
{
"node"
:
">=8"
}
},
"node_modules/electron-to-chromium"
:
{
"version"
:
"1.5.267"
,
"resolved"
:
"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz"
,
...
...
@@ -1328,6 +1623,20 @@
"dev"
:
true
,
"license"
:
"ISC"
},
"node_modules/enhanced-resolve"
:
{
"version"
:
"5.19.0"
,
"resolved"
:
"https://repo.huaweicloud.com/repository/npm/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz"
,
"integrity"
:
"sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg=="
,
"dev"
:
true
,
"license"
:
"MIT"
,
"dependencies"
:
{
"graceful-fs"
:
"^4.2.4"
,
"tapable"
:
"^2.3.0"
},
"engines"
:
{
"node"
:
">=10.13.0"
}
},
"node_modules/esbuild"
:
{
"version"
:
"0.25.12"
,
"resolved"
:
"https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz"
,
...
...
@@ -1437,6 +1746,23 @@
"node"
:
">=6.9.0"
}
},
"node_modules/graceful-fs"
:
{
"version"
:
"4.2.11"
,
"resolved"
:
"https://repo.huaweicloud.com/repository/npm/graceful-fs/-/graceful-fs-4.2.11.tgz"
,
"integrity"
:
"sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
,
"dev"
:
true
,
"license"
:
"ISC"
},
"node_modules/jiti"
:
{
"version"
:
"2.6.1"
,
"resolved"
:
"https://repo.huaweicloud.com/repository/npm/jiti/-/jiti-2.6.1.tgz"
,
"integrity"
:
"sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="
,
"dev"
:
true
,
"license"
:
"MIT"
,
"bin"
:
{
"jiti"
:
"lib/jiti-cli.mjs"
}
},
"node_modules/js-tokens"
:
{
"version"
:
"4.0.0"
,
"resolved"
:
"https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz"
,
...
...
@@ -1470,6 +1796,267 @@
"node"
:
">=6"
}
},
"node_modules/lightningcss"
:
{
"version"
:
"1.30.2"
,
"resolved"
:
"https://repo.huaweicloud.com/repository/npm/lightningcss/-/lightningcss-1.30.2.tgz"
,
"integrity"
:
"sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ=="
,
"dev"
:
true
,
"license"
:
"MPL-2.0"
,
"dependencies"
:
{
"detect-libc"
:
"^2.0.3"
},
"engines"
:
{
"node"
:
">= 12.0.0"
},
"funding"
:
{
"type"
:
"opencollective"
,
"url"
:
"https://opencollective.com/parcel"
},
"optionalDependencies"
:
{
"lightningcss-android-arm64"
:
"1.30.2"
,
"lightningcss-darwin-arm64"
:
"1.30.2"
,
"lightningcss-darwin-x64"
:
"1.30.2"
,
"lightningcss-freebsd-x64"
:
"1.30.2"
,
"lightningcss-linux-arm-gnueabihf"
:
"1.30.2"
,
"lightningcss-linux-arm64-gnu"
:
"1.30.2"
,
"lightningcss-linux-arm64-musl"
:
"1.30.2"
,
"lightningcss-linux-x64-gnu"
:
"1.30.2"
,
"lightningcss-linux-x64-musl"
:
"1.30.2"
,
"lightningcss-win32-arm64-msvc"
:
"1.30.2"
,
"lightningcss-win32-x64-msvc"
:
"1.30.2"
}
},
"node_modules/lightningcss-android-arm64"
:
{
"version"
:
"1.30.2"
,
"resolved"
:
"https://repo.huaweicloud.com/repository/npm/lightningcss-android-arm64/-/lightningcss-android-arm64-1.30.2.tgz"
,
"integrity"
:
"sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A=="
,
"cpu"
:
[
"arm64"
],
"dev"
:
true
,
"license"
:
"MPL-2.0"
,
"optional"
:
true
,
"os"
:
[
"android"
],
"engines"
:
{
"node"
:
">= 12.0.0"
},
"funding"
:
{
"type"
:
"opencollective"
,
"url"
:
"https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-darwin-arm64"
:
{
"version"
:
"1.30.2"
,
"resolved"
:
"https://repo.huaweicloud.com/repository/npm/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz"
,
"integrity"
:
"sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA=="
,
"cpu"
:
[
"arm64"
],
"dev"
:
true
,
"license"
:
"MPL-2.0"
,
"optional"
:
true
,
"os"
:
[
"darwin"
],
"engines"
:
{
"node"
:
">= 12.0.0"
},
"funding"
:
{
"type"
:
"opencollective"
,
"url"
:
"https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-darwin-x64"
:
{
"version"
:
"1.30.2"
,
"resolved"
:
"https://repo.huaweicloud.com/repository/npm/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz"
,
"integrity"
:
"sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ=="
,
"cpu"
:
[
"x64"
],
"dev"
:
true
,
"license"
:
"MPL-2.0"
,
"optional"
:
true
,
"os"
:
[
"darwin"
],
"engines"
:
{
"node"
:
">= 12.0.0"
},
"funding"
:
{
"type"
:
"opencollective"
,
"url"
:
"https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-freebsd-x64"
:
{
"version"
:
"1.30.2"
,
"resolved"
:
"https://repo.huaweicloud.com/repository/npm/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.2.tgz"
,
"integrity"
:
"sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA=="
,
"cpu"
:
[
"x64"
],
"dev"
:
true
,
"license"
:
"MPL-2.0"
,
"optional"
:
true
,
"os"
:
[
"freebsd"
],
"engines"
:
{
"node"
:
">= 12.0.0"
},
"funding"
:
{
"type"
:
"opencollective"
,
"url"
:
"https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-linux-arm-gnueabihf"
:
{
"version"
:
"1.30.2"
,
"resolved"
:
"https://repo.huaweicloud.com/repository/npm/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.2.tgz"
,
"integrity"
:
"sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA=="
,
"cpu"
:
[
"arm"
],
"dev"
:
true
,
"license"
:
"MPL-2.0"
,
"optional"
:
true
,
"os"
:
[
"linux"
],
"engines"
:
{
"node"
:
">= 12.0.0"
},
"funding"
:
{
"type"
:
"opencollective"
,
"url"
:
"https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-linux-arm64-gnu"
:
{
"version"
:
"1.30.2"
,
"resolved"
:
"https://repo.huaweicloud.com/repository/npm/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.2.tgz"
,
"integrity"
:
"sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A=="
,
"cpu"
:
[
"arm64"
],
"dev"
:
true
,
"license"
:
"MPL-2.0"
,
"optional"
:
true
,
"os"
:
[
"linux"
],
"engines"
:
{
"node"
:
">= 12.0.0"
},
"funding"
:
{
"type"
:
"opencollective"
,
"url"
:
"https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-linux-arm64-musl"
:
{
"version"
:
"1.30.2"
,
"resolved"
:
"https://repo.huaweicloud.com/repository/npm/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.2.tgz"
,
"integrity"
:
"sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA=="
,
"cpu"
:
[
"arm64"
],
"dev"
:
true
,
"license"
:
"MPL-2.0"
,
"optional"
:
true
,
"os"
:
[
"linux"
],
"engines"
:
{
"node"
:
">= 12.0.0"
},
"funding"
:
{
"type"
:
"opencollective"
,
"url"
:
"https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-linux-x64-gnu"
:
{
"version"
:
"1.30.2"
,
"resolved"
:
"https://repo.huaweicloud.com/repository/npm/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.2.tgz"
,
"integrity"
:
"sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w=="
,
"cpu"
:
[
"x64"
],
"dev"
:
true
,
"license"
:
"MPL-2.0"
,
"optional"
:
true
,
"os"
:
[
"linux"
],
"engines"
:
{
"node"
:
">= 12.0.0"
},
"funding"
:
{
"type"
:
"opencollective"
,
"url"
:
"https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-linux-x64-musl"
:
{
"version"
:
"1.30.2"
,
"resolved"
:
"https://repo.huaweicloud.com/repository/npm/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.2.tgz"
,
"integrity"
:
"sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA=="
,
"cpu"
:
[
"x64"
],
"dev"
:
true
,
"license"
:
"MPL-2.0"
,
"optional"
:
true
,
"os"
:
[
"linux"
],
"engines"
:
{
"node"
:
">= 12.0.0"
},
"funding"
:
{
"type"
:
"opencollective"
,
"url"
:
"https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-win32-arm64-msvc"
:
{
"version"
:
"1.30.2"
,
"resolved"
:
"https://repo.huaweicloud.com/repository/npm/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.2.tgz"
,
"integrity"
:
"sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ=="
,
"cpu"
:
[
"arm64"
],
"dev"
:
true
,
"license"
:
"MPL-2.0"
,
"optional"
:
true
,
"os"
:
[
"win32"
],
"engines"
:
{
"node"
:
">= 12.0.0"
},
"funding"
:
{
"type"
:
"opencollective"
,
"url"
:
"https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-win32-x64-msvc"
:
{
"version"
:
"1.30.2"
,
"resolved"
:
"https://repo.huaweicloud.com/repository/npm/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.2.tgz"
,
"integrity"
:
"sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw=="
,
"cpu"
:
[
"x64"
],
"dev"
:
true
,
"license"
:
"MPL-2.0"
,
"optional"
:
true
,
"os"
:
[
"win32"
],
"engines"
:
{
"node"
:
">= 12.0.0"
},
"funding"
:
{
"type"
:
"opencollective"
,
"url"
:
"https://opencollective.com/parcel"
}
},
"node_modules/lru-cache"
:
{
"version"
:
"5.1.1"
,
"resolved"
:
"https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz"
,
...
...
@@ -1489,6 +2076,16 @@
"react"
:
"^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
"node_modules/magic-string"
:
{
"version"
:
"0.30.21"
,
"resolved"
:
"https://repo.huaweicloud.com/repository/npm/magic-string/-/magic-string-0.30.21.tgz"
,
"integrity"
:
"sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="
,
"dev"
:
true
,
"license"
:
"MIT"
,
"dependencies"
:
{
"@jridgewell/sourcemap-codec"
:
"^1.5.5"
}
},
"node_modules/ms"
:
{
"version"
:
"2.1.3"
,
"resolved"
:
"https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"
,
...
...
@@ -1684,6 +2281,20 @@
"dev"
:
true
,
"license"
:
"MIT"
},
"node_modules/tapable"
:
{
"version"
:
"2.3.0"
,
"resolved"
:
"https://repo.huaweicloud.com/repository/npm/tapable/-/tapable-2.3.0.tgz"
,
"integrity"
:
"sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="
,
"dev"
:
true
,
"license"
:
"MIT"
,
"engines"
:
{
"node"
:
">=6"
},
"funding"
:
{
"type"
:
"opencollective"
,
"url"
:
"https://opencollective.com/webpack"
}
},
"node_modules/tinyglobby"
:
{
"version"
:
"0.2.15"
,
"resolved"
:
"https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz"
,
...
...
z-image-generator/package.json
View file @
63e61bf
...
...
@@ -14,6 +14,7 @@
"react-dom"
:
"^19.2.3"
},
"devDependencies"
:
{
"@tailwindcss/postcss"
:
"^4.1.18"
,
"@types/node"
:
"^22.14.0"
,
"@vitejs/plugin-react"
:
"^5.0.0"
,
"autoprefixer"
:
"^10.4.24"
,
...
...
z-image-generator/postcss.config.js
View file @
63e61bf
export
default
{
plugins
:
{
tailwindcss
:
{},
'@tailwindcss/postcss'
:
{},
autoprefixer
:
{},
},
}
...
...
Please
register
or
login
to post a comment