Files
eSIM-Tools/netlify.toml
Abner 4c8ab4b916 📝 docs: 规范 Simyo 客户端与接口注释表述
将注释与测试描述改为中性技术说明,仅保留接口路径与配置语义。
2026-07-22 19:26:13 +08:00

190 lines
6.7 KiB
TOML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
[build]
# 构建命令
command = "npm run build --silent"
# 发布目录:仅暴露构建后的 dist 输出
publish = "dist"
# Functions目录
functions = "netlify/functions"
# Edge Functions 目录
edge_functions = "netlify/edge-functions"
[build.environment]
# 固定 Node 版本,避免二进制依赖(如 sharp在 Node 22 下编译耗时
NODE_VERSION = "20.12.2"
# 安装时减少无关输出与提示
NPM_FLAGS = "--no-audit --no-fund --omit=optional"
# 重定向和重写规则
[[redirects]]
# Giffgaff eSIM页面 - 模块化版本
from = "/giffgaff"
to = "/src/giffgaff/giffgaff_modular.html"
status = 200
[[redirects]]
# Simyo eSIM页面 - 模块化版本
from = "/simyo"
to = "/src/simyo/simyo_modular.html"
status = 200
[[redirects]]
# 根路径重定向到选择页面
from = "/"
to = "/index.html"
status = 200
# API代理重定向用于解决CORS问题
# 通用 Simyo API 代理 (webapi - 新版API)
# 代理层覆盖 User-Agent浏览器无法可靠设置 UA
# 与 src/simyo/js/modules/client-identity.js 保持同步
[[redirects]]
from = "/api/simyo/*"
to = "https://appapi.simyo.nl/webapi/api/v1/:splat"
status = 200
force = true
headers = {X-Forwarded-Host = "appapi.simyo.nl", User-Agent = "MijnSimyoFT/4.28.0 (iOS 18.2; iPhone12,8)"}
# 旧版 simyoapi 路径兼容
[[redirects]]
from = "/api/simyo/legacy/*"
to = "https://appapi.simyo.nl/simyoapi/api/v1/:splat"
status = 200
force = true
headers = {X-Forwarded-Host = "appapi.simyo.nl", User-Agent = "MijnSimyoFT/4.28.0 (iOS 18.2; iPhone12,8)"}
[[headers]]
# 限制 Simyo 代理仅允许指定站点跨域访问
for = "/api/simyo/*"
[headers.values]
Access-Control-Allow-Origin = "https://esim.cosr.eu.org"
Access-Control-Allow-Headers = "Content-Type, Authorization, Accept, X-Client-Token, X-Client-Platform, X-Client-Version, X-Device-ID, X-Session-Token"
Access-Control-Allow-Methods = "GET, POST, OPTIONS"
Vary = "Origin"
# 将 /bff/* 映射到 Edge Function bff-proxy
[[edge_functions]]
path = "/bff/*"
function = "bff-proxy"
# Markdown for Agents检测 Accept: text/markdown 请求
[[edge_functions]]
path = "/"
function = "markdown-negotiation"
[[redirects]]
from = "/api/giffgaff/*"
to = "https://api.giffgaff.com/:splat"
status = 200
force = true
headers = {X-Forwarded-Host = "api.giffgaff.com"}
[[headers]]
for = "/api/giffgaff/*"
[headers.values]
# giffgaff 直连不受此限制,保持通用放行
Access-Control-Allow-Origin = "*"
Access-Control-Allow-Headers = "Content-Type, Authorization"
Access-Control-Allow-Methods = "GET, POST, OPTIONS"
[[redirects]]
from = "/api/giffgaff-id/*"
to = "https://id.giffgaff.com/:splat"
status = 200
force = true
headers = {X-Forwarded-Host = "id.giffgaff.com"}
[[headers]]
for = "/api/giffgaff-id/*"
[headers.values]
Access-Control-Allow-Origin = "*"
Access-Control-Allow-Headers = "Content-Type, Authorization"
Access-Control-Allow-Methods = "GET, POST, OPTIONS"
[[redirects]]
from = "/api/giffgaff-public/*"
to = "https://publicapi.giffgaff.com/:splat"
status = 200
force = true
headers = {X-Forwarded-Host = "publicapi.giffgaff.com"}
[[headers]]
for = "/api/giffgaff-public/*"
[headers.values]
Access-Control-Allow-Origin = "*"
Access-Control-Allow-Headers = "Content-Type, Authorization"
Access-Control-Allow-Methods = "GET, POST, OPTIONS"
# favicon 根路径重定向(浏览器默认请求 /favicon.ico
[[redirects]]
from = "/favicon.ico"
to = "/src/assets/favicon.ico"
status = 200
# OG 社交分享图片重定向
[[redirects]]
from = "/og-image.png"
to = "/src/assets/og-image.png"
status = 200
# 处理SPA路由兜底 404
[[redirects]]
from = "/*"
to = "/index.html"
status = 404
# 静态资源长期缓存CSS/JS/字体/图片)
[[headers]]
for = "/src/styles/*"
[headers.values]
Cache-Control = "public, max-age=31536000, immutable"
[[headers]]
for = "/src/js/*"
[headers.values]
Cache-Control = "public, max-age=31536000, immutable"
[[headers]]
for = "/src/assets/*"
[headers.values]
Cache-Control = "public, max-age=31536000, immutable"
[[headers]]
for = "/dist/*"
[headers.values]
Cache-Control = "public, max-age=31536000, immutable"
# HTML 页面:短缓存 + stale-while-revalidate
[[headers]]
for = "/*.html"
[headers.values]
Cache-Control = "public, max-age=300, stale-while-revalidate=86400"
# 安全头部
[[headers]]
for = "/*"
[headers.values]
X-Frame-Options = "DENY"
X-XSS-Protection = "1; mode=block"
X-Content-Type-Options = "nosniff"
Referrer-Policy = "strict-origin-when-cross-origin"
# 生产 CSP包含 unsafe-inline 是因为部分页面仍有内联样式和脚本(如内联 CSS、runtime 兜底脚本),
# 迁移至 nonce/hash 策略需模板注入机制支持,当前暂保留 unsafe-inline
# connect-src 必须包含 cdn.jsdelivr.netBootstrap CSS/JS 的 sourceMappingURL 会发起 connect
Content-Security-Policy = "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net https://www.googletagmanager.com https://www.google.com https://www.gstatic.com https://browser.sentry-cdn.com https://sentry.io https://*.sentry.io https://challenges.cloudflare.com; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://cdnjs.cloudflare.com https://fonts.googleapis.com; img-src 'self' data: https:; connect-src 'self' https://cdn.jsdelivr.net https://cdnjs.cloudflare.com https://browser.sentry-cdn.com https://www.google-analytics.com https://analytics.google.com https://stats.g.doubleclick.net https://www.googletagmanager.com https://qrcode.show https://api.qrserver.com https://appapi.simyo.nl https://api.giffgaff.com https://id.giffgaff.com https://publicapi.giffgaff.com https://www.google.com https://www.gstatic.com https://challenges.cloudflare.com https://sentry.io https://*.sentry.io; font-src 'self' data: https://cdn.jsdelivr.net https://cdnjs.cloudflare.com https://fonts.gstatic.com; frame-src 'self' https://challenges.cloudflare.com https://www.google.com https://*.sentry.io; worker-src 'self' blob:; child-src 'self' blob:; manifest-src 'self';"
# Agent 发现 Link 响应头 (RFC 8288)
[[headers]]
for = "/"
[headers.values]
Link = "</.well-known/api-catalog>; rel=\"api-catalog\", </.well-known/oauth-protected-resource>; rel=\"oauth-protected-resource\", </.well-known/mcp/server-card.json>; rel=\"mcp-server-card\", </.well-known/agent-skills/index.json>; rel=\"agent-skills\""
# Markdown for Agents 支持头部
[[headers]]
for = "/"
[headers.values]
Vary = "Accept"
[[headers]]
for = "/manifest.webmanifest"
[headers.values]
Content-Type = "application/manifest+json; charset=utf-8"