diff --git a/.env.example b/.env.example index 2b70954..58797ff 100644 --- a/.env.example +++ b/.env.example @@ -1,6 +1,11 @@ +# 本地开发:复制为 .dev.vars(Wrangler 自动加载,勿提交) +# cp .env.example .dev.vars +# +# 生产部署:敏感项用 wrangler secret put +# wrangler secret put GITHUB_TOKEN + GITHUB_TOKEN=ghp_your_personal_access_token GITHUB_OWNER=shumengya GITHUB_REPO=Web2App DEFAULT_BRANCH=main -PORT=3001 MAX_UPLOAD_MB=50 diff --git a/.github/scripts/generate-app-icons.mjs b/.github/scripts/generate-app-icons.mjs index 9879cfb..9393113 100644 --- a/.github/scripts/generate-app-icons.mjs +++ b/.github/scripts/generate-app-icons.mjs @@ -8,7 +8,7 @@ const root = path.resolve(__dirname, "../.."); const distDir = path.join(root, "template", "dist"); const templateDir = path.join(root, "template"); -const ICON_PRIORITY = ["logo.png", "favicon.ico"]; +const ICON_PRIORITY = ["logo.png", "logo.jpg", "logo.jpeg", "favicon.ico"]; function findIconSource(baseDir) { for (const name of ICON_PRIORITY) { diff --git a/.github/scripts/prepare-template.mjs b/.github/scripts/prepare-template.mjs index 0dbe976..b687bf8 100644 --- a/.github/scripts/prepare-template.mjs +++ b/.github/scripts/prepare-template.mjs @@ -19,6 +19,17 @@ if (!jobId || !appNameZh || !appNameEn || !appIdentifier) { process.exit(1); } +function readAppVersion(jobId) { + const versionFile = path.join(root, "builds", jobId, "version.txt"); + if (fs.existsSync(versionFile)) { + const fromFile = fs.readFileSync(versionFile, "utf8").trim(); + if (fromFile) return fromFile; + } + const fromEnv = (process.env.APP_VERSION ?? "").trim(); + return fromEnv || "1.0.0"; +} + +const appVersion = readAppVersion(jobId); const zipPath = path.join(root, "builds", jobId, "site.zip"); const distDir = path.join(root, "template", "dist"); const confPath = path.join(root, "template", "src-tauri", "tauri.conf.json"); @@ -46,6 +57,15 @@ if (!fs.existsSync(indexPath)) { process.exit(1); } +const buildDir = path.join(root, "builds", jobId); +for (const iconName of ["logo.png", "logo.jpg", "logo.jpeg", "favicon.ico"]) { + const iconSrc = path.join(buildDir, iconName); + if (fs.existsSync(iconSrc)) { + fs.copyFileSync(iconSrc, path.join(distDir, iconName)); + console.log(`Copied uploaded icon: builds/${jobId}/${iconName}`); + } +} + function toSafeBinaryName(name, fallback) { const ascii = name.replace(/[^a-zA-Z0-9_-]+/g, ""); return (ascii || fallback).slice(0, 64); @@ -57,7 +77,7 @@ function patchTauriConfig(filePath) { conf.productName = appNameZh; conf.mainBinaryName = safeBinaryName; conf.identifier = appIdentifier; - conf.version = "1.0.0"; + conf.version = appVersion; if (conf.app?.windows?.[0]) { conf.app.windows[0].title = appNameZh; } diff --git a/.github/workflows/build-app.yml b/.github/workflows/build-app.yml index 2c0e2b0..d8e8109 100644 --- a/.github/workflows/build-app.yml +++ b/.github/workflows/build-app.yml @@ -28,6 +28,7 @@ env: APP_NAME: ${{ inputs.app_name }} APP_NAME_EN: ${{ inputs.app_name_en }} APP_IDENTIFIER: ${{ inputs.app_identifier }} + APP_VERSION: ${{ inputs.app_version }} NDK_VERSION: "27.2.12479018" jobs: @@ -176,7 +177,7 @@ jobs: tag_name: build-${{ inputs.job_id }} name: Web2App ${{ inputs.app_name }} (${{ inputs.job_id }}) body: | - Automated build for **${{ inputs.app_name }}** (English: `${{ inputs.app_name_en }}`, ID: `${{ inputs.app_identifier }}`). + Automated build for **${{ inputs.app_name }}** (English: `${{ inputs.app_name_en }}`, version: `${{ inputs.app_version }}`, ID: `${{ inputs.app_identifier }}`). - Windows desktop installer/portable binary - Android APK (signed for sideload install) diff --git a/.gitignore b/.gitignore index 7a7c8a1..8335722 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,14 @@ node_modules/ -web/dist/ -server/dist/ +frontend/dist/ +!frontend/dist/index.html uploads/ data/ .env +.dev.vars *.db *.db-journal .DS_Store +.wrangler/ target/ template/dist/* -!template/dist/index.html \ No newline at end of file +!template/dist/index.html diff --git a/README.md b/README.md index 9c18417..5cd0a4a 100644 --- a/README.md +++ b/README.md @@ -2,83 +2,111 @@ 将已构建好的静态网页(zip,入口 `index.html`)转换为 **Windows 桌面应用** 与 **Android APK**。本仓库包含: -- `web/`:上传与构建状态页面 -- `server/`:Express API,负责 zip 校验、GitHub 上传与 workflow 触发 +- `frontend/`:React + Vite 上传与构建状态页面(文档风格 UI) +- `worker/`:Cloudflare Worker API(zip 校验、GitHub 上传、workflow 触发) - `template/`:最小 Tauri 2 壳,CI 中注入用户静态资源后打包 - `.github/workflows/build-app.yml`:并行构建 Windows / Android 并发布 Release ## 架构 -1. 用户在本地网站上传 zip -2. 后端校验 zip 后,通过 GitHub Contents API 上传到 `builds/{jobId}/site.zip` -3. 后端触发 `build-app.yml` workflow +1. 用户访问 Worker 托管的前端并上传 zip +2. Worker 校验 zip 后,通过 GitHub Contents API 上传到 `builds/{jobId}/site.zip` +3. Worker 触发 `build-app.yml` workflow 4. GitHub Actions 解压 zip 到 `template/dist/`,构建 Windows 与 Android -5. `finalize` job 创建 Release:`build-{jobId}`,并返回下载链接 +5. `finalize` job 创建 Release:`build-{jobId}`,前端轮询并展示下载链接 + +本地/生产均由 **一个 Worker** 提供 `/api/*` 与静态资源(`wrangler deploy` 一键部署)。 ## 前置条件 - Node.js 20+ +- [Cloudflare 账号](https://dash.cloudflare.com/) 与 [Wrangler CLI](https://developers.cloudflare.com/workers/wrangler/) - 一个 GitHub 仓库(建议名称 `Web2App`) -- Personal Access Token,权限至少包含: - - `repo` - - `workflow` +- Personal Access Token,权限至少包含:`repo`、`workflow` -## 快速开始 +## 快速开始(本地) -### 1. 初始化 GitHub 仓库 +### 1. 安装依赖 ```bash -git init -git add . -git commit -m "init web2app platform" -git branch -M main -git remote add origin https://github.com//Web2App.git -git push -u origin main +npm install ``` -### 2. 配置环境变量 +### 2. 配置密钥 ```bash -cp .env.example .env +cp .dev.vars.example .dev.vars ``` -编辑 `.env`: +编辑 `.dev.vars`(Wrangler 本地开发自动加载): ```env GITHUB_TOKEN=ghp_xxx GITHUB_OWNER=your-github-username GITHUB_REPO=Web2App DEFAULT_BRANCH=main -PORT=3001 MAX_UPLOAD_MB=50 ``` -### 3. 安装依赖并启动 +### 3. 初始化 D1(本地) ```bash -npm install +npm run db:migrate:local +``` + +### 4. 构建前端并启动 + +```bash +npm run build -w frontend npm run dev ``` -- 前端: -- 后端: +- 前端开发服务器:(`/api` 代理到 Worker `8787`) +- Worker: -### 4. 上传测试 +首次 `wrangler dev` 前需存在 `frontend/dist`(`npm run build -w frontend`)。 -准备一个 zip,根目录包含 `index.html`,也可使用 `examples/sample-site/` 打包: +### 5. 上传测试 + +准备一个 zip,根目录包含 `index.html`,也可使用 `examples/sample-site/` 打包。 + +## 部署到 Cloudflare + +### 1. 登录并创建 D1 ```bash -cd examples/sample-site -powershell Compress-Archive -Path * -DestinationPath ../sample-site.zip -Force +wrangler login +wrangler d1 create web2app ``` -在网页中填写应用名称并上传 zip。 +将命令输出的 `database_id` 写入根目录 `wrangler.toml` 中对应 `[[d1_databases]]` 条目(若 Wrangler 未自动写入)。 + +```bash +npm run db:migrate:remote +``` + +### 2. 配置生产密钥 + +```bash +wrangler secret put GITHUB_TOKEN +``` + +在 `wrangler.toml` 的 `[vars]` 中设置 `GITHUB_OWNER`、`GITHUB_REPO`(或使用 `wrangler secret put` 存放全部变量)。 + +### 3. 一键部署 + +```bash +npm run deploy +``` + +等价于:构建 `frontend/dist` → `wrangler deploy`(Worker API + 静态资源 + D1 绑定)。 ## API | 方法 | 路径 | 说明 | |------|------|------| -| `POST` | `/api/builds` | `multipart/form-data`: `file`, `appNameZh`, `appNameEn`, 可选 `identifier` | +| `GET` | `/api/health` | 健康检查 | +| `POST` | `/api/builds` | `multipart/form-data`: `file`, `appNameZh`, `appNameEn`, `appVersion`(默认当天如 `2026.5.29`),可选 `identifier`、`icon`(PNG/JPG/ICO) | | `GET` | `/api/builds/:id` | 查询构建状态与下载链接 | | `GET` | `/api/builds` | 最近 20 条构建记录 | @@ -88,7 +116,9 @@ powershell Compress-Archive -Path * -DestinationPath ../sample-site.zip -Force - `job_id` - `app_name` +- `app_name_en` - `app_identifier` +- `app_version` 构建产物发布到 Release tag:`build-{job_id}`。 @@ -100,20 +130,10 @@ powershell Compress-Archive -Path * -DestinationPath ../sample-site.zip -Force 2. `favicon.ico` 3. 若都未找到,使用模板内置默认图标 -找到后 CI 会执行 `tauri icon` 生成 Windows / Android 所需的多尺寸图标。 +### Android 签名 -### Android 签名与安装 - -- CI 先构建未签名 APK,再用 `apksigner` **签名**,可直接侧载安装(不修改 Gradle 配置,避免构建失败) -- 未配置 Secrets 时,workflow 会生成临时 CI 证书(密码 `web2app-ci`,仅适合 demo) -- 生产环境建议在仓库 Settings → Secrets 配置: - -| Secret | 说明 | -|--------|------| -| `ANDROID_KEYSTORE_BASE64` | `.jks` 文件 base64 | -| `ANDROID_KEYSTORE_PASSWORD` | keystore 密码 | -| `ANDROID_KEY_PASSWORD` | key 密码 | -| `ANDROID_KEY_ALIAS` | 别名,默认 `web2app` | +- CI 先构建未签名 APK,再用 `apksigner` 签名 +- 生产环境建议在仓库 Settings → Secrets 配置 `ANDROID_KEYSTORE_BASE64` 等 本地生成 keystore: @@ -121,54 +141,35 @@ powershell Compress-Archive -Path * -DestinationPath ../sample-site.zip -Force bash scripts/generate-android-keystore.sh web2app-release.jks web2app ``` -- 首次 Android 构建会在 CI 中执行 `tauri android init` -- Android 构建依赖 NDK / SDK,workflow 已预装常见组件 - -### 手动验证 workflow - -在 GitHub 仓库 Actions 页选择 **Build App**,手动填写: - -- `job_id`: 任意已上传目录名(需先存在 `builds/{job_id}/site.zip`) -- `app_name`: 演示应用 -- `app_name_en`: Demo App -- `app_identifier`: com.web2app.demo - -## 本地数据 - -- SQLite:`data/web2app.db` -- 上传临时文件:内存处理,不持久化到磁盘 - -## Demo 限制 - -- 无登录鉴权,仅适合本地/内网 demo -- GitHub Actions 有排队时间与额度限制 -- 大 zip 会短暂占用仓库空间(finalize 会尝试删除 `site.zip`) -- 未配置自有证书时,各次 CI 构建可能使用不同签名,无法覆盖安装旧版 APK - ## 目录结构 ``` Web2App/ -├── web/ # Vite + React 前端 -├── server/ # Express 后端 +├── frontend/ # React + Vite 前端 +├── worker/ # Cloudflare Worker API + D1 migrations +├── wrangler.toml # 统一部署配置 ├── template/ # Tauri 2 模板 -├── .github/workflows/ # CI 构建 -├── examples/ # 示例静态站点 -└── data/ # 本地 SQLite(运行时生成) +├── .github/workflows/ # CI 构建(未随 Worker 迁移改动) +└── examples/ # 示例静态站点 ``` ## 常见问题 +**`wrangler dev` 找不到静态资源** + +- 运行 `npm run build -w frontend` + **workflow_dispatch 返回 404** -- 确认 workflow 文件已在默认分支 +- 确认 workflow 已在默认分支 - 确认 `DEFAULT_BRANCH` 与仓库默认分支一致 +**D1 表不存在** + +- 本地:`npm run db:migrate:local` +- 远程:`npm run db:migrate:remote` + **Release 没有下载链接** - 等待 `finalize` job 完成 - 检查 Windows / Android job 是否都成功 - -**zip 校验失败** - -- 确保 `index.html` 在 zip 根目录,或仅套一层文件夹 diff --git a/web/index.html b/frontend/index.html similarity index 100% rename from web/index.html rename to frontend/index.html diff --git a/web/package.json b/frontend/package.json similarity index 93% rename from web/package.json rename to frontend/package.json index 1c4ece8..c25d0be 100644 --- a/web/package.json +++ b/frontend/package.json @@ -1,5 +1,5 @@ { - "name": "web2app-web", + "name": "web2app-frontend", "private": true, "version": "0.1.0", "type": "module", diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx new file mode 100644 index 0000000..55e392f --- /dev/null +++ b/frontend/src/App.tsx @@ -0,0 +1,17 @@ +import { Route, Routes } from "react-router-dom"; +import Layout from "./components/Layout"; +import BuildList from "./pages/BuildList"; +import JobStatus from "./pages/JobStatus"; +import Upload from "./pages/Upload"; + +export default function App() { + return ( + + }> + } /> + } /> + } /> + + + ); +} diff --git a/web/src/api.ts b/frontend/src/api/client.ts similarity index 73% rename from web/src/api.ts rename to frontend/src/api/client.ts index de65dda..2528380 100644 --- a/web/src/api.ts +++ b/frontend/src/api/client.ts @@ -1,3 +1,5 @@ +const API_BASE = import.meta.env.VITE_API_BASE ?? ""; + export type BuildStatus = | "pending" | "queued" @@ -10,6 +12,7 @@ export interface Build { appName: string; appNameEn: string; appIdentifier: string; + appVersion: string; status: BuildStatus; workflowRunId: number | null; windowsUrl: string | null; @@ -29,15 +32,21 @@ interface CreateBuildResponse { error?: string; } +function apiUrl(path: string): string { + return `${API_BASE}${path}`; +} + export async function createBuild(formData: FormData): Promise<{ id: string }> { let response: Response; try { - response = await fetch("/api/builds", { + response = await fetch(apiUrl("/api/builds"), { method: "POST", body: formData, }); } catch { - throw new Error("无法连接后端服务,请确认已运行 npm run dev 且 server 已启动"); + throw new Error( + "无法连接后端,请确认已运行 npm run dev 且 wrangler 已启动", + ); } const data = (await readJson(response)) as CreateBuildResponse; @@ -48,7 +57,7 @@ export async function createBuild(formData: FormData): Promise<{ id: string }> { } export async function fetchBuild(id: string): Promise { - const response = await fetch(`/api/builds/${id}`); + const response = await fetch(apiUrl(`/api/builds/${id}`)); const data = (await readJson(response)) as Build; if (!response.ok) { const errorData = data as Build & ApiErrorResponse; @@ -57,6 +66,15 @@ export async function fetchBuild(id: string): Promise { return data; } +export async function fetchBuilds(): Promise { + const response = await fetch(apiUrl("/api/builds")); + const data = (await readJson(response)) as { builds: Build[] }; + if (!response.ok) { + throw new Error("Failed to load builds"); + } + return data.builds; +} + async function readJson(response: Response): Promise { const text = await response.text(); if (!text) return {}; diff --git a/frontend/src/components/Layout.tsx b/frontend/src/components/Layout.tsx new file mode 100644 index 0000000..5843cf3 --- /dev/null +++ b/frontend/src/components/Layout.tsx @@ -0,0 +1,27 @@ +import { Link, Outlet } from "react-router-dom"; + +export default function Layout() { + return ( +
+
+
+ + Web2App + + +
+
+
+
+ +
+
+
+ 静态网页 zip → Windows / Android 原生应用 +
+
+ ); +} diff --git a/frontend/src/lib/version.ts b/frontend/src/lib/version.ts new file mode 100644 index 0000000..72a23d9 --- /dev/null +++ b/frontend/src/lib/version.ts @@ -0,0 +1,4 @@ +/** 默认版本号:当前日期,格式如 2026.5.29 */ +export function getDefaultAppVersion(date = new Date()): string { + return `${date.getFullYear()}.${date.getMonth() + 1}.${date.getDate()}`; +} diff --git a/web/src/main.tsx b/frontend/src/main.tsx similarity index 91% rename from web/src/main.tsx rename to frontend/src/main.tsx index efbf46d..4c5524b 100644 --- a/web/src/main.tsx +++ b/frontend/src/main.tsx @@ -2,7 +2,7 @@ import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; import { BrowserRouter } from "react-router-dom"; import App from "./App"; -import "./styles.css"; +import "./styles/doc.css"; createRoot(document.getElementById("root")!).render( diff --git a/frontend/src/pages/BuildList.tsx b/frontend/src/pages/BuildList.tsx new file mode 100644 index 0000000..13f3f46 --- /dev/null +++ b/frontend/src/pages/BuildList.tsx @@ -0,0 +1,45 @@ +import { useEffect, useState } from "react"; +import { Link } from "react-router-dom"; +import { fetchBuilds, statusLabel, type Build } from "../api/client"; + +export default function BuildList() { + const [builds, setBuilds] = useState([]); + const [error, setError] = useState(null); + + useEffect(() => { + fetchBuilds() + .then(setBuilds) + .catch((err) => + setError(err instanceof Error ? err.message : "加载失败"), + ); + }, []); + + return ( + <> +

构建记录

+

最近 20 条构建任务。

+ +
+ {error ?

{error}

: null} + {!error && builds.length === 0 ? ( +

暂无构建记录。

+ ) : null} + {builds.length > 0 ? ( +
    + {builds.map((build) => ( +
  • + + {build.appName} ({build.appNameEn}) + +
    + v{build.appVersion} · {build.id} · {statusLabel(build.status)}{" "} + · {new Date(build.createdAt).toLocaleString()} +
    +
  • + ))} +
+ ) : null} +
+ + ); +} diff --git a/frontend/src/pages/JobStatus.tsx b/frontend/src/pages/JobStatus.tsx new file mode 100644 index 0000000..6d101c9 --- /dev/null +++ b/frontend/src/pages/JobStatus.tsx @@ -0,0 +1,150 @@ +import { useEffect, useState } from "react"; +import { Link, useParams } from "react-router-dom"; +import { fetchBuild, statusLabel, type Build } from "../api/client"; + +export default function JobStatus() { + const { id } = useParams<{ id: string }>(); + const [build, setBuild] = useState(null); + const [error, setError] = useState(null); + + useEffect(() => { + if (!id) return; + + let cancelled = false; + + async function poll() { + try { + const data = await fetchBuild(id!); + if (cancelled) return; + setBuild(data); + setError(null); + + if (data.status === "completed" || data.status === "failed") { + return; + } + + window.setTimeout(poll, 5000); + } catch (err) { + if (cancelled) return; + setError(err instanceof Error ? err.message : "加载失败"); + window.setTimeout(poll, 5000); + } + } + + poll(); + return () => { + cancelled = true; + }; + }, [id]); + + if (!id) { + return

缺少任务 ID

; + } + + return ( + <> +
+

+ 构建任务 +

+ 返回上传 +
+ + {error ?

{error}

: null} + +
+ {build ? ( + <> +
+
+
任务 ID
+
+ {build.id} +
+
+
+
应用中文名
+
{build.appName}
+
+
+
应用英文名
+
{build.appNameEn}
+
+
+
Bundle ID
+
+ {build.appIdentifier} +
+
+
+
版本号
+
+ {build.appVersion} +
+
+
+
状态
+
+ + {statusLabel(build.status)} + +
+
+
+ + {build.status === "completed" ? ( + <> +

下载安装包

+
+ {build.windowsUrl ? ( + + 下载 Windows 版 + + ) : ( + Windows 安装包尚未就绪 + )} + {build.androidUrl ? ( + + 下载 Android 版 + + ) : ( + Android 安装包尚未就绪 + )} +
+ + ) : null} + + {build.status === "failed" ? ( +
+

{build.error ?? "构建失败,请查看 GitHub Actions 日志。"}

+ {build.actionsUrl ? ( + + 查看 Actions 日志 + + ) : null} +
+ ) : null} + + {build.status !== "completed" && build.status !== "failed" ? ( +

+ 正在轮询 GitHub Actions 状态,请稍候… +

+ ) : null} + + ) : ( +

加载任务信息…

+ )} +
+ + ); +} diff --git a/frontend/src/pages/Upload.tsx b/frontend/src/pages/Upload.tsx new file mode 100644 index 0000000..6ff12c5 --- /dev/null +++ b/frontend/src/pages/Upload.tsx @@ -0,0 +1,153 @@ +import { FormEvent, useEffect, useState } from "react"; +import { useNavigate } from "react-router-dom"; +import { createBuild } from "../api/client"; +import { getDefaultAppVersion } from "../lib/version"; + +export default function Upload() { + const navigate = useNavigate(); + const [appNameZh, setAppNameZh] = useState(""); + const [appNameEn, setAppNameEn] = useState(""); + const [appVersion, setAppVersion] = useState(() => getDefaultAppVersion()); + const [identifier, setIdentifier] = useState(""); + const [file, setFile] = useState(null); + const [icon, setIcon] = useState(null); + const [iconPreview, setIconPreview] = useState(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + + useEffect(() => { + if (!icon) { + setIconPreview(null); + return; + } + const url = URL.createObjectURL(icon); + setIconPreview(url); + return () => URL.revokeObjectURL(url); + }, [icon]); + + async function onSubmit(event: FormEvent) { + event.preventDefault(); + if (!file) { + setError("请选择 zip 文件"); + return; + } + + setLoading(true); + setError(null); + + try { + const formData = new FormData(); + formData.append("file", file); + formData.append("appNameZh", appNameZh); + formData.append("appNameEn", appNameEn); + formData.append("appVersion", appVersion.trim()); + if (identifier.trim()) { + formData.append("identifier", identifier.trim()); + } + if (icon) { + formData.append("icon", icon); + } + + const result = await createBuild(formData); + navigate(`/jobs/${result.id}`); + } catch (err) { + setError(err instanceof Error ? err.message : "上传失败"); + } finally { + setLoading(false); + } + } + + return ( + <> +

上传静态站点

+

+ 将包含 index.html 的 zip 打包为 Windows 与 Android 安装包。 +

+ +
+

使用说明

+

+ 压缩包需包含 index.html(根目录或单层文件夹内),默认不超过 50MB。 + 可单独上传应用图标(PNG / JPG / ICO,优先于 zip 内图标),版本号默认取当天日期(如 + 2026.5.29)。中文名用于展示,英文名用于安装包与 Bundle ID。 +

+
+ +
+

构建参数

+
+ + + + + + {iconPreview ? ( +
+ 图标预览 + {icon?.name} +
+ ) : null} + + {error ?

{error}

: null} + +
+
+ + ); +} diff --git a/frontend/src/styles/doc.css b/frontend/src/styles/doc.css new file mode 100644 index 0000000..3bd1096 --- /dev/null +++ b/frontend/src/styles/doc.css @@ -0,0 +1,375 @@ +:root { + color-scheme: light; + --bg: #fafafa; + --surface: #ffffff; + --text: #1a1a1a; + --muted: #5c5c5c; + --border: #e5e5e5; + --accent: #2563eb; + --accent-hover: #1d4ed8; + --danger: #b91c1c; + --danger-bg: #fef2f2; + --success: #15803d; + --warning: #a16207; + --radius: 8px; + --font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", + Arial, "Noto Sans SC", sans-serif; + --mono: ui-monospace, "Cascadia Code", "Segoe UI Mono", monospace; + --content-max: 42rem; + --page-pad: 1rem; +} + +*, +*::before, +*::after { + box-sizing: border-box; +} + +html { + -webkit-text-size-adjust: 100%; +} + +body { + margin: 0; + font-family: var(--font); + font-size: 1rem; + line-height: 1.6; + color: var(--text); + background: var(--bg); +} + +a { + color: var(--accent); + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +.app-shell { + min-height: 100vh; + display: flex; + flex-direction: column; +} + +.site-header { + border-bottom: 1px solid var(--border); + background: var(--surface); + padding: 0.75rem var(--page-pad); +} + +.site-header-inner { + max-width: var(--content-max); + margin: 0 auto; + display: flex; + flex-wrap: wrap; + align-items: baseline; + justify-content: space-between; + gap: 0.5rem 1rem; +} + +.site-brand { + font-weight: 600; + font-size: 1.125rem; + color: var(--text); + text-decoration: none; +} + +.site-brand:hover { + text-decoration: none; + color: var(--accent); +} + +.site-nav { + display: flex; + gap: 1rem; + font-size: 0.9375rem; +} + +.site-main { + flex: 1; + padding: 1.5rem var(--page-pad) 3rem; +} + +.content { + max-width: var(--content-max); + margin: 0 auto; +} + +.page-title { + margin: 0 0 0.25rem; + font-size: 1.75rem; + font-weight: 700; + letter-spacing: -0.02em; + line-height: 1.25; +} + +.page-lead { + margin: 0 0 1.5rem; + color: var(--muted); + font-size: 1rem; +} + +.doc-section { + background: var(--surface); + border: 1px solid var(--border); + border-radius: var(--radius); + padding: 1.25rem 1.25rem; + margin-bottom: 1.25rem; +} + +.doc-section h2 { + margin: 0 0 0.75rem; + font-size: 1.125rem; + font-weight: 600; +} + +.doc-section h3 { + margin: 1.25rem 0 0.5rem; + font-size: 1rem; + font-weight: 600; +} + +.prose { + margin: 0 0 1rem; + color: var(--muted); + font-size: 0.9375rem; +} + +.prose:last-child { + margin-bottom: 0; +} + +.form { + display: flex; + flex-direction: column; + gap: 1rem; +} + +.form label { + display: flex; + flex-direction: column; + gap: 0.375rem; + font-size: 0.875rem; + font-weight: 500; + color: var(--text); +} + +.form input[type="text"], +.form input[type="file"] { + font: inherit; + padding: 0.625rem 0.75rem; + border: 1px solid var(--border); + border-radius: var(--radius); + background: var(--surface); + min-height: 44px; +} + +.form input[type="file"] { + padding: 0.5rem; +} + +.btn { + display: inline-flex; + align-items: center; + justify-content: center; + min-height: 44px; + padding: 0.625rem 1.25rem; + font: inherit; + font-weight: 500; + font-size: 0.9375rem; + border: none; + border-radius: var(--radius); + cursor: pointer; + text-decoration: none; + transition: background 0.15s ease; +} + +.btn-primary { + background: var(--accent); + color: #fff; +} + +.btn-primary:hover:not(:disabled) { + background: var(--accent-hover); +} + +.btn-primary:disabled { + opacity: 0.6; + cursor: not-allowed; +} + +.btn-secondary { + background: var(--surface); + color: var(--text); + border: 1px solid var(--border); +} + +.btn-secondary:hover { + background: var(--bg); + text-decoration: none; +} + +.error-text { + margin: 0; + color: var(--danger); + font-size: 0.875rem; +} + +.error-box { + margin-top: 1rem; + padding: 1rem; + background: var(--danger-bg); + border: 1px solid #fecaca; + border-radius: var(--radius); + font-size: 0.9375rem; +} + +.error-box p { + margin: 0 0 0.5rem; +} + +.meta-list { + margin: 0; + display: grid; + gap: 0.75rem; +} + +.meta-list > div { + display: grid; + grid-template-columns: minmax(7rem, 9rem) 1fr; + gap: 0.5rem 1rem; + align-items: baseline; + font-size: 0.9375rem; +} + +.meta-list dt { + margin: 0; + color: var(--muted); + font-weight: 500; +} + +.meta-list dd { + margin: 0; + word-break: break-word; +} + +.badge { + display: inline-block; + padding: 0.125rem 0.5rem; + font-size: 0.8125rem; + font-weight: 500; + border-radius: 4px; + background: #f3f4f6; + color: var(--text); +} + +.badge-pending, +.badge-queued { + background: #fef3c7; + color: var(--warning); +} + +.badge-in_progress { + background: #dbeafe; + color: var(--accent); +} + +.badge-completed { + background: #dcfce7; + color: var(--success); +} + +.badge-failed { + background: var(--danger-bg); + color: var(--danger); +} + +.download-row { + display: flex; + flex-direction: column; + gap: 0.75rem; + margin-top: 0.5rem; +} + +.muted { + color: var(--muted); + font-size: 0.875rem; +} + +.status-toolbar { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + align-items: center; + gap: 0.75rem; + margin-bottom: 1rem; +} + +.build-list { + list-style: none; + margin: 0; + padding: 0; +} + +.build-list li { + border-top: 1px solid var(--border); + padding: 0.75rem 0; +} + +.build-list li:first-child { + border-top: none; + padding-top: 0; +} + +.build-list a { + font-weight: 500; +} + +.build-list .meta-line { + font-size: 0.8125rem; + color: var(--muted); + margin-top: 0.25rem; +} + +.icon-preview { + display: flex; + align-items: center; + gap: 0.75rem; + padding: 0.5rem 0; +} + +.icon-preview img { + object-fit: contain; + border: 1px solid var(--border); + border-radius: var(--radius); + background: var(--bg); +} + +.site-footer { + border-top: 1px solid var(--border); + padding: 1rem var(--page-pad); + text-align: center; + font-size: 0.8125rem; + color: var(--muted); +} + +@media (min-width: 768px) { + :root { + --page-pad: 1.5rem; + } + + .page-title { + font-size: 2rem; + } + + .doc-section { + padding: 1.5rem 1.75rem; + } + + .download-row { + flex-direction: row; + flex-wrap: wrap; + } +} diff --git a/frontend/src/vite-env.d.ts b/frontend/src/vite-env.d.ts new file mode 100644 index 0000000..7a7f1cd --- /dev/null +++ b/frontend/src/vite-env.d.ts @@ -0,0 +1,9 @@ +/// + +interface ImportMetaEnv { + readonly VITE_API_BASE?: string; +} + +interface ImportMeta { + readonly env: ImportMetaEnv; +} diff --git a/web/tsconfig.app.json b/frontend/tsconfig.app.json similarity index 100% rename from web/tsconfig.app.json rename to frontend/tsconfig.app.json diff --git a/frontend/tsconfig.app.tsbuildinfo b/frontend/tsconfig.app.tsbuildinfo new file mode 100644 index 0000000..354c8c5 --- /dev/null +++ b/frontend/tsconfig.app.tsbuildinfo @@ -0,0 +1 @@ +{"root":["./src/app.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/api/client.ts","./src/components/layout.tsx","./src/lib/version.ts","./src/pages/buildlist.tsx","./src/pages/jobstatus.tsx","./src/pages/upload.tsx"],"version":"5.6.3"} \ No newline at end of file diff --git a/web/tsconfig.json b/frontend/tsconfig.json similarity index 100% rename from web/tsconfig.json rename to frontend/tsconfig.json diff --git a/web/tsconfig.node.json b/frontend/tsconfig.node.json similarity index 68% rename from web/tsconfig.node.json rename to frontend/tsconfig.node.json index 7366cef..2ab3f37 100644 --- a/web/tsconfig.node.json +++ b/frontend/tsconfig.node.json @@ -4,7 +4,9 @@ "lib": ["ES2023"], "module": "ESNext", "skipLibCheck": true, - "moduleResolution": "bundler" + "moduleResolution": "bundler", + "strict": true, + "noEmit": true }, "include": ["vite.config.ts"] } diff --git a/web/tsconfig.node.tsbuildinfo b/frontend/tsconfig.node.tsbuildinfo similarity index 100% rename from web/tsconfig.node.tsbuildinfo rename to frontend/tsconfig.node.tsbuildinfo diff --git a/web/vite.config.ts b/frontend/vite.config.ts similarity index 70% rename from web/vite.config.ts rename to frontend/vite.config.ts index 41952ff..4454d1e 100644 --- a/web/vite.config.ts +++ b/frontend/vite.config.ts @@ -7,9 +7,13 @@ export default defineConfig({ port: 5173, proxy: { "/api": { - target: "http://127.0.0.1:3001", + target: "http://127.0.0.1:8787", changeOrigin: true, }, }, }, + build: { + outDir: "dist", + emptyOutDir: true, + }, }); diff --git a/package-lock.json b/package-lock.json index 87ea6ba..1612e55 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,15 +8,31 @@ "name": "web2app", "version": "0.1.0", "workspaces": [ - "web", - "server", + "frontend", + "worker", "template" ], "devDependencies": { "adm-zip": "^0.5.17", "concurrently": "^9.1.2", "typescript": "~5.6.2", - "wait-on": "^8.0.5" + "wrangler": "^3.99.0" + } + }, + "frontend": { + "name": "web2app-frontend", + "version": "0.1.0", + "dependencies": { + "react": "^19.0.0", + "react-dom": "^19.0.0", + "react-router-dom": "^7.1.1" + }, + "devDependencies": { + "@types/react": "^19.0.2", + "@types/react-dom": "^19.0.2", + "@vitejs/plugin-react": "^4.3.4", + "typescript": "~5.6.2", + "vite": "^6.0.3" } }, "node_modules/@babel/code-frame": { @@ -301,6 +317,199 @@ "node": ">=6.9.0" } }, + "node_modules/@cloudflare/kv-asset-handler": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.3.4.tgz", + "integrity": "sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q==", + "dev": true, + "license": "MIT OR Apache-2.0", + "dependencies": { + "mime": "^3.0.0" + }, + "engines": { + "node": ">=16.13" + } + }, + "node_modules/@cloudflare/kv-asset-handler/node_modules/mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@cloudflare/unenv-preset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@cloudflare/unenv-preset/-/unenv-preset-2.0.2.tgz", + "integrity": "sha512-nyzYnlZjjV5xT3LizahG1Iu6mnrCaxglJ04rZLpDwlDVDZ7v46lNsfxhV3A/xtfgQuSHmLnc6SVI+KwBpc3Lwg==", + "dev": true, + "license": "MIT OR Apache-2.0", + "peerDependencies": { + "unenv": "2.0.0-rc.14", + "workerd": "^1.20250124.0" + }, + "peerDependenciesMeta": { + "workerd": { + "optional": true + } + } + }, + "node_modules/@cloudflare/workerd-darwin-64": { + "version": "1.20250718.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20250718.0.tgz", + "integrity": "sha512-FHf4t7zbVN8yyXgQ/r/GqLPaYZSGUVzeR7RnL28Mwj2djyw2ZergvytVc7fdGcczl6PQh+VKGfZCfUqpJlbi9g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-darwin-arm64": { + "version": "1.20250718.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20250718.0.tgz", + "integrity": "sha512-fUiyUJYyqqp4NqJ0YgGtp4WJh/II/YZsUnEb6vVy5Oeas8lUOxnN+ZOJ8N/6/5LQCVAtYCChRiIrBbfhTn5Z8Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-linux-64": { + "version": "1.20250718.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20250718.0.tgz", + "integrity": "sha512-5+eb3rtJMiEwp08Kryqzzu8d1rUcK+gdE442auo5eniMpT170Dz0QxBrqkg2Z48SFUPYbj+6uknuA5tzdRSUSg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-linux-arm64": { + "version": "1.20250718.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20250718.0.tgz", + "integrity": "sha512-Aa2M/DVBEBQDdATMbn217zCSFKE+ud/teS+fFS+OQqKABLn0azO2qq6ANAHYOIE6Q3Sq4CxDIQr8lGdaJHwUog==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-windows-64": { + "version": "1.20250718.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20250718.0.tgz", + "integrity": "sha512-dY16RXKffmugnc67LTbyjdDHZn5NoTF1yHEf2fN4+OaOnoGSp3N1x77QubTDwqZ9zECWxgQfDLjddcH8dWeFhg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workers-types": { + "version": "4.20260528.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20260528.1.tgz", + "integrity": "sha512-sTNOEN+8DvAOdE7MG3I/TbRGrjZnfbf0aqyTR4wzVi2GEpHTG9DzaK0MSA0z0JS2LmTUSSWimj4mB4cJaYk9rQ==", + "dev": true, + "license": "MIT OR Apache-2.0" + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild-plugins/node-globals-polyfill": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@esbuild-plugins/node-globals-polyfill/-/node-globals-polyfill-0.2.3.tgz", + "integrity": "sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw==", + "dev": true, + "license": "ISC", + "peerDependencies": { + "esbuild": "*" + } + }, + "node_modules/@esbuild-plugins/node-modules-polyfill": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@esbuild-plugins/node-modules-polyfill/-/node-modules-polyfill-0.2.2.tgz", + "integrity": "sha512-LXV7QsWJxRuMYvKbiznh+U1ilIop3g2TeKRzUxOG5X3YITc8JyyTa90BmLwqqv0YnX4v32CSlG+vsziZp9dMvA==", + "dev": true, + "license": "ISC", + "dependencies": { + "escape-string-regexp": "^4.0.0", + "rollup-plugin-node-polyfills": "^0.2.1" + }, + "peerDependencies": { + "esbuild": "*" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.28.0", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz", @@ -314,6 +523,7 @@ "os": [ "aix" ], + "peer": true, "engines": { "node": ">=18" } @@ -331,6 +541,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=18" } @@ -348,6 +559,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=18" } @@ -365,6 +577,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=18" } @@ -382,6 +595,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=18" } @@ -399,6 +613,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=18" } @@ -416,6 +631,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -433,6 +649,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -450,6 +667,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -467,6 +685,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -484,6 +703,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -501,6 +721,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -518,6 +739,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -535,6 +757,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -552,6 +775,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -569,6 +793,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -586,6 +811,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -603,6 +829,7 @@ "os": [ "netbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -620,6 +847,7 @@ "os": [ "netbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -637,6 +865,7 @@ "os": [ "openbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -654,6 +883,7 @@ "os": [ "openbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -671,6 +901,7 @@ "os": [ "openharmony" ], + "peer": true, "engines": { "node": ">=18" } @@ -688,6 +919,7 @@ "os": [ "sunos" ], + "peer": true, "engines": { "node": ">=18" } @@ -705,6 +937,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=18" } @@ -722,6 +955,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=18" } @@ -739,62 +973,435 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=18" } }, - "node_modules/@hapi/address": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@hapi/address/-/address-5.1.1.tgz", - "integrity": "sha512-A+po2d/dVoY7cYajycYI43ZbYMXukuopIsqCjh5QzsBCipDtdofHntljDlpccMjIfTy6UOkg+5KPriwYch2bXA==", + "node_modules/@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", + "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", + "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", + "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", + "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", + "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", + "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", + "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", + "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", + "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", + "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", + "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.0.5" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", + "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", + "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.0.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", + "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", + "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", + "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz", + "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, "dependencies": { - "@hapi/hoek": "^11.0.2" + "@emnapi/runtime": "^1.2.0" }, "engines": { - "node": ">=14.0.0" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@hapi/formula": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@hapi/formula/-/formula-3.0.2.tgz", - "integrity": "sha512-hY5YPNXzw1He7s0iqkRQi+uMGh383CGdyyIGYtB+W5N3KHPXoqychklvHhKCC9M3Xtv0OCs/IHw+r4dcHtBYWw==", + "node_modules/@img/sharp-win32-ia32": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", + "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==", + "cpu": [ + "ia32" + ], "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@hapi/hoek": { - "version": "11.0.7", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-11.0.7.tgz", - "integrity": "sha512-HV5undWkKzcB4RZUusqOpcgxOaq6VOAH7zhhIr2g3G8NF/MlFO75SjOr2NfuSx0Mh40+1FqCkagKLJRykUWoFQ==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@hapi/pinpoint": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@hapi/pinpoint/-/pinpoint-2.0.1.tgz", - "integrity": "sha512-EKQmr16tM8s16vTT3cA5L0kZZcTMU5DUOZTuvpnY738m+jyP3JIUj+Mm1xc1rsLkGBQ/gVnfKYPwOmPg1tUR4Q==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@hapi/tlds": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@hapi/tlds/-/tlds-1.1.6.tgz", - "integrity": "sha512-xdi7A/4NZokvV0ewovme3aUO5kQhW9pQ2YD1hRqZGhhSi5rBv4usHYidVocXSi9eihYsznZxLtAiEYYUL6VBGw==", - "dev": true, - "license": "BSD-3-Clause", + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=14.0.0" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@hapi/topo": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-6.0.2.tgz", - "integrity": "sha512-KR3rD5inZbGMrHmgPxsJ9dbi6zEK+C3ZwUwTa+eMwWLz7oijWUTWD2pMSNNYJAU6Qq+65NkxXjqHr/7LM2Xkqg==", + "node_modules/@img/sharp-win32-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", + "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", + "cpu": [ + "x64" + ], "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/hoek": "^11.0.2" + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" } }, "node_modules/@jridgewell/gen-mapping": { @@ -847,347 +1454,6 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@octokit/app": { - "version": "15.1.6", - "resolved": "https://registry.npmjs.org/@octokit/app/-/app-15.1.6.tgz", - "integrity": "sha512-WELCamoCJo9SN0lf3SWZccf68CF0sBNPQuLYmZ/n87p5qvBJDe9aBtr5dHkh7T9nxWZ608pizwsUbypSzZAiUw==", - "license": "MIT", - "dependencies": { - "@octokit/auth-app": "^7.2.1", - "@octokit/auth-unauthenticated": "^6.1.3", - "@octokit/core": "^6.1.5", - "@octokit/oauth-app": "^7.1.6", - "@octokit/plugin-paginate-rest": "^12.0.0", - "@octokit/types": "^14.0.0", - "@octokit/webhooks": "^13.6.1" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/auth-app": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@octokit/auth-app/-/auth-app-7.2.2.tgz", - "integrity": "sha512-p6hJtEyQDCJEPN9ijjhEC/kpFHMHN4Gca9r+8S0S8EJi7NaWftaEmexjxxpT1DFBeJpN4u/5RE22ArnyypupJw==", - "license": "MIT", - "dependencies": { - "@octokit/auth-oauth-app": "^8.1.4", - "@octokit/auth-oauth-user": "^5.1.4", - "@octokit/request": "^9.2.3", - "@octokit/request-error": "^6.1.8", - "@octokit/types": "^14.0.0", - "toad-cache": "^3.7.0", - "universal-github-app-jwt": "^2.2.0", - "universal-user-agent": "^7.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/auth-oauth-app": { - "version": "8.1.4", - "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-app/-/auth-oauth-app-8.1.4.tgz", - "integrity": "sha512-71iBa5SflSXcclk/OL3lJzdt4iFs56OJdpBGEBl1wULp7C58uiswZLV6TdRaiAzHP1LT8ezpbHlKuxADb+4NkQ==", - "license": "MIT", - "dependencies": { - "@octokit/auth-oauth-device": "^7.1.5", - "@octokit/auth-oauth-user": "^5.1.4", - "@octokit/request": "^9.2.3", - "@octokit/types": "^14.0.0", - "universal-user-agent": "^7.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/auth-oauth-device": { - "version": "7.1.5", - "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-device/-/auth-oauth-device-7.1.5.tgz", - "integrity": "sha512-lR00+k7+N6xeECj0JuXeULQ2TSBB/zjTAmNF2+vyGPDEFx1dgk1hTDmL13MjbSmzusuAmuJD8Pu39rjp9jH6yw==", - "license": "MIT", - "dependencies": { - "@octokit/oauth-methods": "^5.1.5", - "@octokit/request": "^9.2.3", - "@octokit/types": "^14.0.0", - "universal-user-agent": "^7.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/auth-oauth-user": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-user/-/auth-oauth-user-5.1.6.tgz", - "integrity": "sha512-/R8vgeoulp7rJs+wfJ2LtXEVC7pjQTIqDab7wPKwVG6+2v/lUnCOub6vaHmysQBbb45FknM3tbHW8TOVqYHxCw==", - "license": "MIT", - "dependencies": { - "@octokit/auth-oauth-device": "^7.1.5", - "@octokit/oauth-methods": "^5.1.5", - "@octokit/request": "^9.2.3", - "@octokit/types": "^14.0.0", - "universal-user-agent": "^7.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/auth-token": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-5.1.2.tgz", - "integrity": "sha512-JcQDsBdg49Yky2w2ld20IHAlwr8d/d8N6NiOXbtuoPCqzbsiJgF633mVUw3x4mo0H5ypataQIX7SFu3yy44Mpw==", - "license": "MIT", - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/auth-unauthenticated": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/@octokit/auth-unauthenticated/-/auth-unauthenticated-6.1.3.tgz", - "integrity": "sha512-d5gWJla3WdSl1yjbfMpET+hUSFCE15qM0KVSB0H1shyuJihf/RL1KqWoZMIaonHvlNojkL9XtLFp8QeLe+1iwA==", - "license": "MIT", - "dependencies": { - "@octokit/request-error": "^6.1.8", - "@octokit/types": "^14.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/core": { - "version": "6.1.6", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-6.1.6.tgz", - "integrity": "sha512-kIU8SLQkYWGp3pVKiYzA5OSaNF5EE03P/R8zEmmrG6XwOg5oBjXyQVVIauQ0dgau4zYhpZEhJrvIYt6oM+zZZA==", - "license": "MIT", - "dependencies": { - "@octokit/auth-token": "^5.0.0", - "@octokit/graphql": "^8.2.2", - "@octokit/request": "^9.2.3", - "@octokit/request-error": "^6.1.8", - "@octokit/types": "^14.0.0", - "before-after-hook": "^3.0.2", - "universal-user-agent": "^7.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/endpoint": { - "version": "10.1.4", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-10.1.4.tgz", - "integrity": "sha512-OlYOlZIsfEVZm5HCSR8aSg02T2lbUWOsCQoPKfTXJwDzcHQBrVBGdGXb89dv2Kw2ToZaRtudp8O3ZIYoaOjKlA==", - "license": "MIT", - "dependencies": { - "@octokit/types": "^14.0.0", - "universal-user-agent": "^7.0.2" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/graphql": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-8.2.2.tgz", - "integrity": "sha512-Yi8hcoqsrXGdt0yObxbebHXFOiUA+2v3n53epuOg1QUgOB6c4XzvisBNVXJSl8RYA5KrDuSL2yq9Qmqe5N0ryA==", - "license": "MIT", - "dependencies": { - "@octokit/request": "^9.2.3", - "@octokit/types": "^14.0.0", - "universal-user-agent": "^7.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/oauth-app": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/@octokit/oauth-app/-/oauth-app-7.1.6.tgz", - "integrity": "sha512-OMcMzY2WFARg80oJNFwWbY51TBUfLH4JGTy119cqiDawSFXSIBujxmpXiKbGWQlvfn0CxE6f7/+c6+Kr5hI2YA==", - "license": "MIT", - "dependencies": { - "@octokit/auth-oauth-app": "^8.1.3", - "@octokit/auth-oauth-user": "^5.1.3", - "@octokit/auth-unauthenticated": "^6.1.2", - "@octokit/core": "^6.1.4", - "@octokit/oauth-authorization-url": "^7.1.1", - "@octokit/oauth-methods": "^5.1.4", - "@types/aws-lambda": "^8.10.83", - "universal-user-agent": "^7.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/oauth-authorization-url": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@octokit/oauth-authorization-url/-/oauth-authorization-url-7.1.1.tgz", - "integrity": "sha512-ooXV8GBSabSWyhLUowlMIVd9l1s2nsOGQdlP2SQ4LnkEsGXzeCvbSbCPdZThXhEFzleGPwbapT0Sb+YhXRyjCA==", - "license": "MIT", - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/oauth-methods": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@octokit/oauth-methods/-/oauth-methods-5.1.5.tgz", - "integrity": "sha512-Ev7K8bkYrYLhoOSZGVAGsLEscZQyq7XQONCBBAl2JdMg7IT3PQn/y8P0KjloPoYpI5UylqYrLeUcScaYWXwDvw==", - "license": "MIT", - "dependencies": { - "@octokit/oauth-authorization-url": "^7.0.0", - "@octokit/request": "^9.2.3", - "@octokit/request-error": "^6.1.8", - "@octokit/types": "^14.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/openapi-types": { - "version": "25.1.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-25.1.0.tgz", - "integrity": "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA==", - "license": "MIT" - }, - "node_modules/@octokit/openapi-webhooks-types": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-webhooks-types/-/openapi-webhooks-types-11.0.0.tgz", - "integrity": "sha512-ZBzCFj98v3SuRM7oBas6BHZMJRadlnDoeFfvm1olVxZnYeU6Vh97FhPxyS5aLh5pN51GYv2I51l/hVUAVkGBlA==", - "license": "MIT" - }, - "node_modules/@octokit/plugin-paginate-graphql": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-graphql/-/plugin-paginate-graphql-5.2.4.tgz", - "integrity": "sha512-pLZES1jWaOynXKHOqdnwZ5ULeVR6tVVCMm+AUbp0htdcyXDU95WbkYdU4R2ej1wKj5Tu94Mee2Ne0PjPO9cCyA==", - "license": "MIT", - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "@octokit/core": ">=6" - } - }, - "node_modules/@octokit/plugin-paginate-rest": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-12.0.0.tgz", - "integrity": "sha512-MPd6WK1VtZ52lFrgZ0R2FlaoiWllzgqFHaSZxvp72NmoDeZ0m8GeJdg4oB6ctqMTYyrnDYp592Xma21mrgiyDA==", - "license": "MIT", - "dependencies": { - "@octokit/types": "^14.0.0" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "@octokit/core": ">=6" - } - }, - "node_modules/@octokit/plugin-rest-endpoint-methods": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-14.0.0.tgz", - "integrity": "sha512-iQt6ovem4b7zZYZQtdv+PwgbL5VPq37th1m2x2TdkgimIDJpsi2A6Q/OI/23i/hR6z5mL0EgisNR4dcbmckSZQ==", - "license": "MIT", - "dependencies": { - "@octokit/types": "^14.0.0" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "@octokit/core": ">=6" - } - }, - "node_modules/@octokit/plugin-retry": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-7.2.1.tgz", - "integrity": "sha512-wUc3gv0D6vNHpGxSaR3FlqJpTXGWgqmk607N9L3LvPL4QjaxDgX/1nY2mGpT37Khn+nlIXdljczkRnNdTTV3/A==", - "license": "MIT", - "dependencies": { - "@octokit/request-error": "^6.1.8", - "@octokit/types": "^14.0.0", - "bottleneck": "^2.15.3" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "@octokit/core": ">=6" - } - }, - "node_modules/@octokit/plugin-throttling": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-10.0.0.tgz", - "integrity": "sha512-Kuq5/qs0DVYTHZuBAzCZStCzo2nKvVRo/TDNhCcpC2TKiOGz/DisXMCvjt3/b5kr6SCI1Y8eeeJTHBxxpFvZEg==", - "license": "MIT", - "dependencies": { - "@octokit/types": "^14.0.0", - "bottleneck": "^2.15.3" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "@octokit/core": "^6.1.3" - } - }, - "node_modules/@octokit/request": { - "version": "9.2.4", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-9.2.4.tgz", - "integrity": "sha512-q8ybdytBmxa6KogWlNa818r0k1wlqzNC+yNkcQDECHvQo8Vmstrg18JwqJHdJdUiHD2sjlwBgSm9kHkOKe2iyA==", - "license": "MIT", - "dependencies": { - "@octokit/endpoint": "^10.1.4", - "@octokit/request-error": "^6.1.8", - "@octokit/types": "^14.0.0", - "fast-content-type-parse": "^2.0.0", - "universal-user-agent": "^7.0.2" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/request-error": { - "version": "6.1.8", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-6.1.8.tgz", - "integrity": "sha512-WEi/R0Jmq+IJKydWlKDmryPcmdYSVjL3ekaiEL1L9eo1sUnqMJ+grqmC9cjk7CA7+b2/T397tO5d8YLOH3qYpQ==", - "license": "MIT", - "dependencies": { - "@octokit/types": "^14.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/types": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-14.1.0.tgz", - "integrity": "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==", - "license": "MIT", - "dependencies": { - "@octokit/openapi-types": "^25.1.0" - } - }, - "node_modules/@octokit/webhooks": { - "version": "13.9.1", - "resolved": "https://registry.npmjs.org/@octokit/webhooks/-/webhooks-13.9.1.tgz", - "integrity": "sha512-Nss2b4Jyn4wB3EAqAPJypGuCJFalz/ZujKBQQ5934To7Xw9xjf4hkr/EAByxQY7hp7MKd790bWGz7XYSTsHmaw==", - "license": "MIT", - "dependencies": { - "@octokit/openapi-webhooks-types": "11.0.0", - "@octokit/request-error": "^6.1.7", - "@octokit/webhooks-methods": "^5.1.1" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/webhooks-methods": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@octokit/webhooks-methods/-/webhooks-methods-5.1.1.tgz", - "integrity": "sha512-NGlEHZDseJTCj8TMMFehzwa9g7On4KJMPVHDSrHxCQumL6uSQR8wIkP/qesv52fXqV1BPf4pTxwtS31ldAt9Xg==", - "license": "MIT", - "engines": { - "node": ">= 18" - } - }, "node_modules/@rolldown/pluginutils": { "version": "1.0.0-beta.27", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", @@ -1584,13 +1850,6 @@ "win32" ] }, - "node_modules/@standard-schema/spec": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", - "dev": true, - "license": "MIT" - }, "node_modules/@tauri-apps/cli": { "version": "2.11.2", "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.11.2.tgz", @@ -1823,22 +2082,6 @@ "node": ">= 10" } }, - "node_modules/@types/adm-zip": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.5.8.tgz", - "integrity": "sha512-RVVH7QvZYbN+ihqZ4kX/dMiowf6o+Jk1fNwiSdx0NahBJLU787zkULhGhJM8mf/obmLGmgdMM0bXsQTmyfbR7Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/aws-lambda": { - "version": "8.10.161", - "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.161.tgz", - "integrity": "sha512-rUYdp+MQwSFocxIOcSsYSF3YYYC/uUpMbCY/mbO21vGqfrEYvNSoPyKYDj6RhXXpPfS0KstW9RwG3qXh9sL7FQ==", - "license": "MIT" - }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -1884,47 +2127,6 @@ "@babel/types": "^7.28.2" } }, - "node_modules/@types/better-sqlite3": { - "version": "7.6.13", - "resolved": "https://registry.npmjs.org/@types/better-sqlite3/-/better-sqlite3-7.6.13.tgz", - "integrity": "sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/body-parser": { - "version": "1.19.6", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", - "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/cors": { - "version": "2.8.19", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", - "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -1932,72 +2134,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/express": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.6.tgz", - "integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^5.0.0", - "@types/serve-static": "^2" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.1.tgz", - "integrity": "sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } - }, - "node_modules/@types/http-errors": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", - "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/multer": { - "version": "1.4.13", - "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.13.tgz", - "integrity": "sha512-bhhdtPw7JqCiEfC9Jimx5LqX9BDIPJEh2q/fQ4bqbBPtyEZYr3cvF22NwG0DmPZNYA0CAf2CnqDB4KIGGpJcaw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/express": "*" - } - }, - "node_modules/@types/node": { - "version": "22.19.19", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.19.tgz", - "integrity": "sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/@types/qs": { - "version": "6.15.1", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.1.tgz", - "integrity": "sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/react": { "version": "19.2.15", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.15.tgz", @@ -2018,27 +2154,6 @@ "@types/react": "^19.2.0" } }, - "node_modules/@types/send": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", - "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/serve-static": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-2.2.0.tgz", - "integrity": "sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/http-errors": "*", - "@types/node": "*" - } - }, "node_modules/@vitejs/plugin-react": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", @@ -2060,41 +2175,39 @@ "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "dev": true, "license": "MIT", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" + "bin": { + "acorn": "bin/acorn" }, "engines": { - "node": ">= 0.6" + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" } }, "node_modules/adm-zip": { "version": "0.5.17", "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.17.tgz", "integrity": "sha512-+Ut8d9LLqwEvHHJl1+PIHqoyDxFgVN847JTVM3Izi3xHDWPE4UtzzXysMZQs64DMcrJfBeS/uoEP4AD3HQHnQQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=12.0" } }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -2121,58 +2234,16 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/append-field": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", - "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", - "license": "MIT" - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "license": "MIT" - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/axios": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.16.1.tgz", - "integrity": "sha512-caYkukvroVPO8KrzuJEb50Hm07KwfBZPEC3VeFHTsqWHvKTsy54hjJz9BS/cdaypROE2rH6xvm9mHX4fgWkr3A==", + "node_modules/as-table": { + "version": "1.0.55", + "resolved": "https://registry.npmjs.org/as-table/-/as-table-1.0.55.tgz", + "integrity": "sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==", "dev": true, "license": "MIT", "dependencies": { - "follow-redirects": "^1.16.0", - "form-data": "^4.0.5", - "https-proxy-agent": "^5.0.1", - "proxy-from-env": "^2.1.0" + "printable-characters": "^1.0.42" } }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/baseline-browser-mapping": { "version": "2.10.32", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.32.tgz", @@ -2186,100 +2257,11 @@ "node": ">=6.0.0" } }, - "node_modules/before-after-hook": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-3.0.2.tgz", - "integrity": "sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A==", - "license": "Apache-2.0" - }, - "node_modules/better-sqlite3": { - "version": "11.10.0", - "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-11.10.0.tgz", - "integrity": "sha512-EwhOpyXiOEL/lKzHz9AW1msWFNzGc/z+LzeB3/jnFJpxu+th2yqvzsSWas1v9jgs9+xiXJcD5A8CJxAG2TaghQ==", - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "bindings": "^1.5.0", - "prebuild-install": "^7.1.1" - } - }, - "node_modules/bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "license": "MIT", - "dependencies": { - "file-uri-to-path": "1.0.0" - } - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "license": "MIT", - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/bl/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/body-parser": { - "version": "1.20.5", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.5.tgz", - "integrity": "sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==", - "license": "MIT", - "dependencies": { - "bytes": "~3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "~1.2.0", - "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", - "on-finished": "~2.4.1", - "qs": "~6.15.1", - "raw-body": "~2.5.3", - "type-is": "~1.6.18", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/bottleneck": { - "version": "2.19.5", - "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", - "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==", + "node_modules/blake3-wasm": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/blake3-wasm/-/blake3-wasm-2.1.5.tgz", + "integrity": "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==", + "dev": true, "license": "MIT" }, "node_modules/browserslist": { @@ -2316,85 +2298,6 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "license": "MIT" - }, - "node_modules/busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", - "dependencies": { - "streamsearch": "^1.1.0" - }, - "engines": { - "node": ">=10.16.0" - } - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/caniuse-lite": { "version": "1.0.30001793", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz", @@ -2446,12 +2349,6 @@ "node": ">=8" } }, - "node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "license": "ISC" - }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -2467,6 +2364,21 @@ "node": ">=12" } }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -2487,32 +2399,16 @@ "dev": true, "license": "MIT" }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "engines": [ - "node >= 0.8" - ], - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" } }, "node_modules/concurrently": { @@ -2540,27 +2436,6 @@ "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" } }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -2572,40 +2447,12 @@ "version": "0.7.2", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" } }, - "node_modules/cookie-signature": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", - "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", - "license": "MIT" - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "license": "MIT" - }, - "node_modules/cors": { - "version": "2.8.6", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", - "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", - "license": "MIT", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, "node_modules/csstype": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", @@ -2613,6 +2460,13 @@ "dev": true, "license": "MIT" }, + "node_modules/data-uri-to-buffer": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-2.0.2.tgz", + "integrity": "sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==", + "dev": true, + "license": "MIT" + }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -2631,100 +2485,24 @@ } } }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "license": "MIT", - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "license": "MIT", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "node_modules/defu": { + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", + "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "license": "MIT", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } + "license": "MIT" }, "node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, "license": "Apache-2.0", + "optional": true, "engines": { "node": ">=8" } }, - "node_modules/dotenv": { - "version": "16.6.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", - "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "license": "MIT" - }, "node_modules/electron-to-chromium": { "version": "1.5.362", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.362.tgz", @@ -2739,70 +2517,6 @@ "dev": true, "license": "MIT" }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", - "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", - "license": "MIT", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", - "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/esbuild": { "version": "0.28.0", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.0.tgz", @@ -2810,6 +2524,7 @@ "dev": true, "hasInstallScript": true, "license": "MIT", + "peer": true, "bin": { "esbuild": "bin/esbuild" }, @@ -2855,105 +2570,44 @@ "node": ">=6" } }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT" - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" - } - }, - "node_modules/expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "license": "(MIT OR WTFPL)", - "engines": { - "node": ">=6" - } - }, - "node_modules/express": { - "version": "4.22.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.22.2.tgz", - "integrity": "sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q==", - "license": "MIT", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "~1.20.5", - "content-disposition": "~0.5.4", - "content-type": "~1.0.4", - "cookie": "~0.7.1", - "cookie-signature": "~1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.3.1", - "fresh": "~0.5.2", - "http-errors": "~2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "~2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "~0.1.12", - "proxy-addr": "~2.0.7", - "qs": "~6.15.1", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "~0.19.0", - "serve-static": "~1.16.2", - "setprototypeof": "1.2.0", - "statuses": "~2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "node_modules/estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "dev": true, "license": "MIT" }, - "node_modules/fast-content-type-parse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-2.0.1.tgz", - "integrity": "sha512-nGqtvLrj5w0naR6tDPfB4cUmYCqouzyQiz6C5y/LtcDllJdrcc6WaWW6iXyIIOErTa/XRybj28aasdn4LkVk6Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], + "node_modules/exit-hook": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-2.2.1.tgz", + "integrity": "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/exsolve": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz", + "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==", + "dev": true, "license": "MIT" }, "node_modules/fdir": { @@ -2974,105 +2628,10 @@ } } }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "license": "MIT" - }, - "node_modules/finalhandler": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", - "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "~2.4.1", - "parseurl": "~1.3.3", - "statuses": "~2.0.2", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/follow-redirects": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", - "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/form-data": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", - "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", - "dev": true, - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "node_modules/fflate": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.3.tgz", + "integrity": "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==", "license": "MIT" }, "node_modules/fsevents": { @@ -3090,15 +2649,6 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -3119,60 +2669,23 @@ "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "license": "MIT", + "node_modules/get-source": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/get-source/-/get-source-2.0.12.tgz", + "integrity": "sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==", + "dev": true, + "license": "Unlicense", "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "data-uri-to-buffer": "^2.0.0", + "source-map": "^0.6.1" } }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", - "license": "MIT" - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true, + "license": "BSD-2-Clause" }, "node_modules/has-flag": { "version": "4.0.0", @@ -3184,132 +2697,13 @@ "node": ">=8" } }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "node_modules/is-arrayish": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz", + "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==", "dev": true, "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", - "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/http-errors": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", - "license": "MIT", - "dependencies": { - "depd": "~2.0.0", - "inherits": "~2.0.4", - "setprototypeof": "~1.2.0", - "statuses": "~2.0.2", - "toidentifier": "~1.0.1" - }, - "engines": { - "node": ">= 0.8" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "license": "ISC" - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "license": "MIT", - "engines": { - "node": ">= 0.10" - } + "optional": true }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", @@ -3321,31 +2715,6 @@ "node": ">=8" } }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "license": "MIT" - }, - "node_modules/joi": { - "version": "18.2.1", - "resolved": "https://registry.npmjs.org/joi/-/joi-18.2.1.tgz", - "integrity": "sha512-2/OKlogiESf2Nh3TFCrRjrr9z1DRHeW0I+KReF67+4J0Ns+8hBtHRmoWAZ2OFU6I5+TWLEe6sVlSdXPjHm5UbQ==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/address": "^5.1.1", - "@hapi/formula": "^3.0.2", - "@hapi/hoek": "^11.0.7", - "@hapi/pinpoint": "^2.0.1", - "@hapi/tlds": "^1.1.1", - "@hapi/topo": "^6.0.2", - "@standard-schema/spec": "^1.1.0" - }, - "engines": { - "node": ">= 20" - } - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -3379,13 +2748,6 @@ "node": ">=6" } }, - "node_modules/lodash": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", - "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", - "dev": true, - "license": "MIT" - }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -3396,137 +2758,57 @@ "yallist": "^3.0.2" } }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", - "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "node_modules/magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "dev": true, "license": "MIT", "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" + "sourcemap-codec": "^1.4.8" } }, - "node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "node_modules/miniflare": { + "version": "3.20250718.3", + "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.20250718.3.tgz", + "integrity": "sha512-JuPrDJhwLrNLEJiNLWO7ZzJrv/Vv9kZuwMYCfv0LskQDM6Eonw4OvywO3CH/wCGjgHzha/qyjUh8JQ068TjDgQ==", + "dev": true, "license": "MIT", "dependencies": { - "minimist": "^1.2.6" + "@cspotcode/source-map-support": "0.8.1", + "acorn": "8.14.0", + "acorn-walk": "8.3.2", + "exit-hook": "2.2.1", + "glob-to-regexp": "0.4.1", + "stoppable": "1.1.0", + "undici": "^5.28.5", + "workerd": "1.20250718.0", + "ws": "8.18.0", + "youch": "3.3.4", + "zod": "3.22.3" }, "bin": { - "mkdirp": "bin/cmd.js" + "miniflare": "bootstrap.js" + }, + "engines": { + "node": ">=16.13" } }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "license": "MIT" - }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, "license": "MIT" }, - "node_modules/multer": { - "version": "1.4.5-lts.2", - "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.2.tgz", - "integrity": "sha512-VzGiVigcG9zUAoCNU+xShztrlr1auZOlurXynNvO9GiWD1/mTBbUljOKY+qMeazBqXgRnjzeEgJI/wyjJUHg9A==", - "deprecated": "Multer 1.x is impacted by a number of vulnerabilities, which have been patched in 2.x. You should upgrade to the latest 2.x version.", + "node_modules/mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "dev": true, "license": "MIT", - "dependencies": { - "append-field": "^1.0.0", - "busboy": "^1.0.0", - "concat-stream": "^1.5.2", - "mkdirp": "^0.5.4", - "object-assign": "^4.1.1", - "type-is": "^1.6.4", - "xtend": "^4.0.0" - }, - "engines": { - "node": ">= 6.0.0" + "bin": { + "mustache": "bin/mustache" } }, "node_modules/nanoid": { @@ -3547,45 +2829,6 @@ "node": "^18 || >=20" } }, - "node_modules/napi-build-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", - "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", - "license": "MIT" - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/node-abi": { - "version": "3.92.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.92.0.tgz", - "integrity": "sha512-KdHvFWZjEKDf0cakgFjebl371GPsISX2oZHcuyKqM7DtogIsHrqKeLTo8wBHxaXRAQlY2PsPlZmfo+9ZCxEREQ==", - "license": "MIT", - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-abi/node_modules/semver": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", - "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/node-releases": { "version": "2.0.46", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.46.tgz", @@ -3596,83 +2839,18 @@ "node": ">=18" } }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } + "node_modules/ohash": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", + "dev": true, + "license": "MIT" }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/octokit": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/octokit/-/octokit-4.1.4.tgz", - "integrity": "sha512-cRvxRte6FU3vAHRC9+PMSY3D+mRAs2Rd9emMoqp70UGRvJRM3sbAoim2IXRZNNsf8wVfn4sGxVBHRAP+JBVX/g==", - "license": "MIT", - "dependencies": { - "@octokit/app": "^15.1.6", - "@octokit/core": "^6.1.5", - "@octokit/oauth-app": "^7.1.6", - "@octokit/plugin-paginate-graphql": "^5.2.4", - "@octokit/plugin-paginate-rest": "^12.0.0", - "@octokit/plugin-rest-endpoint-methods": "^14.0.0", - "@octokit/plugin-retry": "^7.2.1", - "@octokit/plugin-throttling": "^10.0.0", - "@octokit/request-error": "^6.1.8", - "@octokit/types": "^14.0.0", - "@octokit/webhooks": "^13.8.3" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-to-regexp": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", - "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, "license": "MIT" }, "node_modules/picocolors": { @@ -3743,125 +2921,12 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/prebuild-install": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", - "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", - "deprecated": "No longer maintained. Please contact the author of the relevant native addon; alternatives are available.", - "license": "MIT", - "dependencies": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^2.0.0", - "node-abi": "^3.3.0", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - }, - "bin": { - "prebuild-install": "bin.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "license": "MIT" - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "license": "MIT", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/proxy-from-env": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", - "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "node_modules/printable-characters": { + "version": "1.0.42", + "resolved": "https://registry.npmjs.org/printable-characters/-/printable-characters-1.0.42.tgz", + "integrity": "sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/pump": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", - "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/qs": { - "version": "6.15.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", - "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", - "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", - "license": "MIT", - "dependencies": { - "bytes": "~3.1.2", - "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } + "license": "Unlicense" }, "node_modules/react": { "version": "19.2.6", @@ -3945,27 +3010,6 @@ "url": "https://opencollective.com/express" } }, - "node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/readable-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -4021,6 +3065,39 @@ "fsevents": "~2.3.2" } }, + "node_modules/rollup-plugin-inject": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-inject/-/rollup-plugin-inject-3.0.2.tgz", + "integrity": "sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==", + "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-inject.", + "dev": true, + "license": "MIT", + "dependencies": { + "estree-walker": "^0.6.1", + "magic-string": "^0.25.3", + "rollup-pluginutils": "^2.8.1" + } + }, + "node_modules/rollup-plugin-node-polyfills": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-node-polyfills/-/rollup-plugin-node-polyfills-0.2.1.tgz", + "integrity": "sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==", + "dev": true, + "license": "MIT", + "dependencies": { + "rollup-plugin-inject": "^3.0.0" + } + }, + "node_modules/rollup-pluginutils": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", + "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "estree-walker": "^0.6.1" + } + }, "node_modules/rxjs": { "version": "7.8.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", @@ -4031,32 +3108,6 @@ "tslib": "^2.1.0" } }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" - }, "node_modules/scheduler": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", @@ -4073,71 +3124,66 @@ "semver": "bin/semver.js" } }, - "node_modules/send": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", - "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "~0.5.2", - "http-errors": "~2.0.1", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "~2.4.1", - "range-parser": "~1.2.1", - "statuses": "~2.0.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/serve-static": { - "version": "1.16.3", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", - "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", - "license": "MIT", - "dependencies": { - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "~0.19.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/set-cookie-parser": { "version": "2.7.2", "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", "license": "MIT" }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "license": "ISC" + "node_modules/sharp": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz", + "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.3", + "semver": "^7.6.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.33.5", + "@img/sharp-darwin-x64": "0.33.5", + "@img/sharp-libvips-darwin-arm64": "1.0.4", + "@img/sharp-libvips-darwin-x64": "1.0.4", + "@img/sharp-libvips-linux-arm": "1.0.5", + "@img/sharp-libvips-linux-arm64": "1.0.4", + "@img/sharp-libvips-linux-s390x": "1.0.4", + "@img/sharp-libvips-linux-x64": "1.0.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", + "@img/sharp-libvips-linuxmusl-x64": "1.0.4", + "@img/sharp-linux-arm": "0.33.5", + "@img/sharp-linux-arm64": "0.33.5", + "@img/sharp-linux-s390x": "0.33.5", + "@img/sharp-linux-x64": "0.33.5", + "@img/sharp-linuxmusl-arm64": "0.33.5", + "@img/sharp-linuxmusl-x64": "0.33.5", + "@img/sharp-wasm32": "0.33.5", + "@img/sharp-win32-ia32": "0.33.5", + "@img/sharp-win32-x64": "0.33.5" + } + }, + "node_modules/sharp/node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "dev": true, + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } }, "node_modules/shell-quote": { "version": "1.8.3", @@ -4152,121 +3198,25 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "node_modules/simple-swizzle": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz", + "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==", + "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "is-arrayish": "^0.3.1" } }, - "node_modules/side-channel-list": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", - "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.4" - }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/simple-get": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" + "node": ">=0.10.0" } }, "node_modules/source-map-js": { @@ -4279,38 +3229,36 @@ "node": ">=0.10.0" } }, - "node_modules/statuses": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/streamsearch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "deprecated": "Please use @jridgewell/sourcemap-codec instead", + "dev": true, "license": "MIT" }, + "node_modules/stacktracey": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/stacktracey/-/stacktracey-2.2.0.tgz", + "integrity": "sha512-ETyQEz+CzXiLjEbyJqpbp+/T79RQD/6wqFucRBIlVNZfYq2Ay7wbretD4cxpbymZlaPWx58aIhPEY1Cr8DlVvg==", + "dev": true, + "license": "Unlicense", + "dependencies": { + "as-table": "^1.0.36", + "get-source": "^2.0.12" + } + }, + "node_modules/stoppable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", + "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4", + "npm": ">=6" + } + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -4339,15 +3287,6 @@ "node": ">=8" } }, - "node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -4364,48 +3303,6 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/tar-fs": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", - "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", - "license": "MIT", - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "license": "MIT", - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tar-stream/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/tinyglobby": { "version": "0.2.16", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", @@ -4423,24 +3320,6 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/toad-cache": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/toad-cache/-/toad-cache-3.7.1.tgz", - "integrity": "sha512-5DXWzE4Vz7xNHsv+xQ+MGfJYyC78Aok3tEr0MNwHoRf7vZnga1mQXZ4/Nsodld4VR6Wd+VhfmqnNrsRJyYPfrQ==", - "license": "MIT", - "engines": { - "node": ">=20" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, "node_modules/tree-kill": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", @@ -4458,56 +3337,6 @@ "dev": true, "license": "0BSD" }, - "node_modules/tsx": { - "version": "4.22.3", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.3.tgz", - "integrity": "sha512-mdoNxBC/cSQObGGVQ5Bpn5i+yv7j68gk3Nfm3wFjcJg3Z0Mix9jzAFfP12prmm5eVGmDKtp0yyArrs0Q+8gZHg==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "~0.28.0" - }, - "bin": { - "tsx": "dist/cli.mjs" - }, - "engines": { - "node": ">=18.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - } - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "license": "Apache-2.0", - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "license": "MIT", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", - "license": "MIT" - }, "node_modules/typescript": { "version": "5.6.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", @@ -4522,32 +3351,38 @@ "node": ">=14.17" } }, - "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "node_modules/ufo": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz", + "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==", "dev": true, "license": "MIT" }, - "node_modules/universal-github-app-jwt": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/universal-github-app-jwt/-/universal-github-app-jwt-2.2.2.tgz", - "integrity": "sha512-dcmbeSrOdTnsjGjUfAlqNDJrhxXizjAz94ija9Qw8YkZ1uu0d+GoZzyH+Jb9tIIqvGsadUfwg+22k5aDqqwzbw==", - "license": "MIT" - }, - "node_modules/universal-user-agent": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz", - "integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==", - "license": "ISC" - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "node_modules/undici": { + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz", + "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==", + "dev": true, "license": "MIT", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, "engines": { - "node": ">= 0.8" + "node": ">=14.0" + } + }, + "node_modules/unenv": { + "version": "2.0.0-rc.14", + "resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.14.tgz", + "integrity": "sha512-od496pShMen7nOy5VmVJCnq8rptd45vh6Nx/r2iPbrba6pa6p+tS2ywuIHRZ/OBvSbQZB0kWvpO9XBNVFXHD3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "defu": "^6.1.4", + "exsolve": "^1.0.1", + "ohash": "^2.0.10", + "pathe": "^2.0.3", + "ufo": "^1.5.4" } }, "node_modules/update-browserslist-db": { @@ -4581,30 +3416,6 @@ "browserslist": ">= 4.21.0" } }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "license": "MIT" - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/vite": { "version": "6.4.2", "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.2.tgz", @@ -5164,38 +3975,496 @@ "@esbuild/win32-x64": "0.25.12" } }, - "node_modules/wait-on": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-8.0.5.tgz", - "integrity": "sha512-J3WlS0txVHkhLRb2FsmRg3dkMTCV1+M6Xra3Ho7HzZDHpE7DCOnoSoCJsZotrmW3uRMhvIJGSKUKrh/MeF4iag==", - "dev": true, - "license": "MIT", - "dependencies": { - "axios": "^1.12.1", - "joi": "^18.0.1", - "lodash": "^4.17.21", - "minimist": "^1.2.8", - "rxjs": "^7.8.2" - }, - "bin": { - "wait-on": "bin/wait-on" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/web2app-server": { - "resolved": "server", + "node_modules/web2app-frontend": { + "resolved": "frontend", "link": true }, "node_modules/web2app-template": { "resolved": "template", "link": true }, - "node_modules/web2app-web": { - "resolved": "web", + "node_modules/web2app-worker": { + "resolved": "worker", "link": true }, + "node_modules/workerd": { + "version": "1.20250718.0", + "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20250718.0.tgz", + "integrity": "sha512-kqkIJP/eOfDlUyBzU7joBg+tl8aB25gEAGqDap+nFWb+WHhnooxjGHgxPBy3ipw2hnShPFNOQt5lFRxbwALirg==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "bin": { + "workerd": "bin/workerd" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "@cloudflare/workerd-darwin-64": "1.20250718.0", + "@cloudflare/workerd-darwin-arm64": "1.20250718.0", + "@cloudflare/workerd-linux-64": "1.20250718.0", + "@cloudflare/workerd-linux-arm64": "1.20250718.0", + "@cloudflare/workerd-windows-64": "1.20250718.0" + } + }, + "node_modules/wrangler": { + "version": "3.114.17", + "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.114.17.tgz", + "integrity": "sha512-tAvf7ly+tB+zwwrmjsCyJ2pJnnc7SZhbnNwXbH+OIdVas3zTSmjcZOjmLKcGGptssAA3RyTKhcF9BvKZzMUycA==", + "dev": true, + "license": "MIT OR Apache-2.0", + "dependencies": { + "@cloudflare/kv-asset-handler": "0.3.4", + "@cloudflare/unenv-preset": "2.0.2", + "@esbuild-plugins/node-globals-polyfill": "0.2.3", + "@esbuild-plugins/node-modules-polyfill": "0.2.2", + "blake3-wasm": "2.1.5", + "esbuild": "0.17.19", + "miniflare": "3.20250718.3", + "path-to-regexp": "6.3.0", + "unenv": "2.0.0-rc.14", + "workerd": "1.20250718.0" + }, + "bin": { + "wrangler": "bin/wrangler.js", + "wrangler2": "bin/wrangler.js" + }, + "engines": { + "node": ">=16.17.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2", + "sharp": "^0.33.5" + }, + "peerDependencies": { + "@cloudflare/workers-types": "^4.20250408.0" + }, + "peerDependenciesMeta": { + "@cloudflare/workers-types": { + "optional": true + } + } + }, + "node_modules/wrangler/node_modules/@esbuild/android-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", + "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/wrangler/node_modules/@esbuild/android-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", + "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/wrangler/node_modules/@esbuild/android-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", + "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/wrangler/node_modules/@esbuild/darwin-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", + "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/wrangler/node_modules/@esbuild/darwin-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", + "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/wrangler/node_modules/@esbuild/freebsd-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", + "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/wrangler/node_modules/@esbuild/freebsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", + "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/wrangler/node_modules/@esbuild/linux-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", + "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/wrangler/node_modules/@esbuild/linux-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", + "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/wrangler/node_modules/@esbuild/linux-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", + "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/wrangler/node_modules/@esbuild/linux-loong64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", + "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/wrangler/node_modules/@esbuild/linux-mips64el": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", + "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/wrangler/node_modules/@esbuild/linux-ppc64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", + "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/wrangler/node_modules/@esbuild/linux-riscv64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", + "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/wrangler/node_modules/@esbuild/linux-s390x": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", + "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/wrangler/node_modules/@esbuild/linux-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", + "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/wrangler/node_modules/@esbuild/netbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", + "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/wrangler/node_modules/@esbuild/openbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", + "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/wrangler/node_modules/@esbuild/sunos-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", + "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/wrangler/node_modules/@esbuild/win32-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", + "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/wrangler/node_modules/@esbuild/win32-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", + "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/wrangler/node_modules/@esbuild/win32-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", + "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/wrangler/node_modules/esbuild": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", + "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.17.19", + "@esbuild/android-arm64": "0.17.19", + "@esbuild/android-x64": "0.17.19", + "@esbuild/darwin-arm64": "0.17.19", + "@esbuild/darwin-x64": "0.17.19", + "@esbuild/freebsd-arm64": "0.17.19", + "@esbuild/freebsd-x64": "0.17.19", + "@esbuild/linux-arm": "0.17.19", + "@esbuild/linux-arm64": "0.17.19", + "@esbuild/linux-ia32": "0.17.19", + "@esbuild/linux-loong64": "0.17.19", + "@esbuild/linux-mips64el": "0.17.19", + "@esbuild/linux-ppc64": "0.17.19", + "@esbuild/linux-riscv64": "0.17.19", + "@esbuild/linux-s390x": "0.17.19", + "@esbuild/linux-x64": "0.17.19", + "@esbuild/netbsd-x64": "0.17.19", + "@esbuild/openbsd-x64": "0.17.19", + "@esbuild/sunos-x64": "0.17.19", + "@esbuild/win32-arm64": "0.17.19", + "@esbuild/win32-ia32": "0.17.19", + "@esbuild/win32-x64": "0.17.19" + } + }, + "node_modules/wrangler/node_modules/path-to-regexp": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", + "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", + "dev": true, + "license": "MIT" + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -5214,19 +4483,26 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, "license": "MIT", "engines": { - "node": ">=0.4" + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } } }, "node_modules/y18n": { @@ -5275,9 +4551,32 @@ "node": ">=12" } }, + "node_modules/youch": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/youch/-/youch-3.3.4.tgz", + "integrity": "sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cookie": "^0.7.1", + "mustache": "^4.2.0", + "stacktracey": "^2.1.8" + } + }, + "node_modules/zod": { + "version": "3.22.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.3.tgz", + "integrity": "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, "server": { "name": "web2app-server", "version": "0.1.0", + "extraneous": true, "hasInstallScript": true, "dependencies": { "adm-zip": "^0.5.16", @@ -5310,6 +4609,7 @@ "web": { "name": "web2app-web", "version": "0.1.0", + "extraneous": true, "dependencies": { "react": "^19.0.0", "react-dom": "^19.0.0", @@ -5322,6 +4622,17 @@ "typescript": "~5.6.2", "vite": "^6.0.3" } + }, + "worker": { + "name": "web2app-worker", + "version": "0.1.0", + "dependencies": { + "fflate": "^0.8.2", + "nanoid": "^5.0.9" + }, + "devDependencies": { + "@cloudflare/workers-types": "^4.20241127.0" + } } } } diff --git a/package.json b/package.json index f8fe789..722f8a9 100644 --- a/package.json +++ b/package.json @@ -4,22 +4,21 @@ "version": "0.1.0", "type": "module", "workspaces": [ - "web", - "server", + "frontend", + "worker", "template" ], "scripts": { - "dev": "concurrently -n server,web -c blue,green \"npm run dev:server\" \"npm run dev:web:wait\"", - "dev:web:wait": "wait-on http://127.0.0.1:3001/api/health -t 120000 && npm run dev -w web", - "dev:web": "npm run dev -w web", - "dev:server": "npm run dev -w server", - "build": "npm run build -w web && npm run build -w server", - "start": "npm run start -w server" + "dev": "concurrently -n web,worker -c green,blue \"npm run dev -w frontend\" \"wrangler dev\"", + "build": "npm run build -w frontend", + "deploy": "npm run build && wrangler deploy", + "db:migrate:local": "wrangler d1 migrations apply web2app --local", + "db:migrate:remote": "wrangler d1 migrations apply web2app --remote" }, "devDependencies": { "adm-zip": "^0.5.17", "concurrently": "^9.1.2", "typescript": "~5.6.2", - "wait-on": "^8.0.5" + "wrangler": "^3.99.0" } } diff --git a/server/db/index.ts b/server/db/index.ts deleted file mode 100644 index 3c3854b..0000000 --- a/server/db/index.ts +++ /dev/null @@ -1,131 +0,0 @@ -import Database from "better-sqlite3"; -import fs from "node:fs"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; - -const __dirname = path.dirname(fileURLToPath(import.meta.url)); - -export type BuildStatus = - | "pending" - | "queued" - | "in_progress" - | "completed" - | "failed"; - -export interface BuildRecord { - id: string; - app_name: string; - app_name_en: string; - app_identifier: string; - status: BuildStatus; - workflow_run_id: number | null; - windows_url: string | null; - android_url: string | null; - error: string | null; - created_at: string; - updated_at: string; -} - -let db: Database.Database | null = null; - -export function getDb(): Database.Database { - if (db) return db; - - const dataDir = path.resolve(__dirname, "../../data"); - fs.mkdirSync(dataDir, { recursive: true }); - const dbPath = path.join(dataDir, "web2app.db"); - db = new Database(dbPath); - const schema = fs.readFileSync(path.join(__dirname, "schema.sql"), "utf8"); - db.exec(schema); - migrateBuildsTable(db); - return db; -} - -function migrateBuildsTable(database: Database.Database) { - const columns = database - .prepare("PRAGMA table_info(builds)") - .all() as Array<{ name: string }>; - - if (!columns.some((column) => column.name === "app_name_en")) { - database.exec("ALTER TABLE builds ADD COLUMN app_name_en TEXT NOT NULL DEFAULT ''"); - } -} - -export function insertBuild(record: { - id: string; - appName: string; - appNameEn: string; - appIdentifier: string; -}): BuildRecord { - const database = getDb(); - database - .prepare( - `INSERT INTO builds (id, app_name, app_name_en, app_identifier, status) - VALUES (@id, @appName, @appNameEn, @appIdentifier, 'pending')`, - ) - .run(record); - - return getBuild(record.id)!; -} - -export function getBuild(id: string): BuildRecord | null { - const row = getDb() - .prepare("SELECT * FROM builds WHERE id = ?") - .get(id) as BuildRecord | undefined; - return row ?? null; -} - -export function listBuilds(limit = 20): BuildRecord[] { - return getDb() - .prepare("SELECT * FROM builds ORDER BY created_at DESC LIMIT ?") - .all(limit) as BuildRecord[]; -} - -export function updateBuild( - id: string, - patch: Partial< - Pick< - BuildRecord, - | "status" - | "workflow_run_id" - | "windows_url" - | "android_url" - | "error" - > - >, -): BuildRecord | null { - const fields: string[] = []; - const params: Record = { id }; - - for (const [key, value] of Object.entries(patch)) { - if (value !== undefined) { - fields.push(`${key} = @${key}`); - params[key] = value; - } - } - - if (fields.length === 0) return getBuild(id); - - fields.push("updated_at = datetime('now')"); - getDb() - .prepare(`UPDATE builds SET ${fields.join(", ")} WHERE id = @id`) - .run(params); - - return getBuild(id); -} - -export function toPublicBuild(record: BuildRecord) { - return { - id: record.id, - appName: record.app_name, - appNameEn: record.app_name_en || record.app_name, - appIdentifier: record.app_identifier, - status: record.status, - workflowRunId: record.workflow_run_id, - windowsUrl: record.windows_url, - androidUrl: record.android_url, - error: record.error, - createdAt: record.created_at, - updatedAt: record.updated_at, - }; -} diff --git a/server/index.ts b/server/index.ts deleted file mode 100644 index d650c7e..0000000 --- a/server/index.ts +++ /dev/null @@ -1,57 +0,0 @@ -import "./load-env.js"; -import cors from "cors"; -import express from "express"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; -import { MulterError } from "multer"; -import { buildsRouter } from "./routes/builds.js"; - -const app = express(); -const port = Number(process.env.PORT ?? "3001"); - -app.use(cors()); -app.use(express.json()); - -app.get("/api/health", (_req, res) => { - res.json({ ok: true }); -}); - -app.use("/api/builds", buildsRouter); - -app.use((err: unknown, _req: express.Request, res: express.Response, next: express.NextFunction) => { - if (res.headersSent) { - next(err); - return; - } - - if (err instanceof MulterError) { - const status = err.code === "LIMIT_FILE_SIZE" ? 413 : 400; - res.status(status).json({ error: err.message }); - return; - } - - if (err instanceof Error) { - console.error(err); - res.status(500).json({ error: err.message }); - return; - } - - console.error(err); - res.status(500).json({ error: "Internal server error" }); -}); - -const webDist = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../web/dist"); -app.use(express.static(webDist)); -app.get("*", (_req, res, next) => { - if (_req.path.startsWith("/api")) { - next(); - return; - } - res.sendFile(path.join(webDist, "index.html"), (err) => { - if (err) next(); - }); -}); - -app.listen(port, "127.0.0.1", () => { - console.log(`Web2App server listening on http://127.0.0.1:${port}`); -}); diff --git a/server/load-env.ts b/server/load-env.ts deleted file mode 100644 index 62b8518..0000000 --- a/server/load-env.ts +++ /dev/null @@ -1,13 +0,0 @@ -import dotenv from "dotenv"; -import fs from "node:fs"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; - -const serverDir = path.dirname(fileURLToPath(import.meta.url)); -const rootEnv = path.resolve(serverDir, "../.env"); - -if (fs.existsSync(rootEnv)) { - dotenv.config({ path: rootEnv }); -} else { - dotenv.config(); -} diff --git a/server/package.json b/server/package.json deleted file mode 100644 index 619ca8d..0000000 --- a/server/package.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "web2app-server", - "private": true, - "version": "0.1.0", - "type": "module", - "scripts": { - "postinstall": "node -e \"try{require('better-sqlite3')}catch{process.exit(1)}\" || npm rebuild better-sqlite3", - "predev": "npm rebuild better-sqlite3", - "dev": "tsx watch index.ts", - "prebuild": "npm rebuild better-sqlite3", - "build": "tsc", - "prestart": "npm rebuild better-sqlite3", - "start": "node dist/index.js" - }, - "dependencies": { - "adm-zip": "^0.5.16", - "better-sqlite3": "^11.8.1", - "cors": "^2.8.5", - "dotenv": "^16.4.7", - "express": "^4.21.2", - "multer": "^1.4.5-lts.1", - "nanoid": "^5.1.0", - "octokit": "^4.1.2" - }, - "devDependencies": { - "@types/adm-zip": "^0.5.7", - "@types/better-sqlite3": "^7.6.12", - "@types/cors": "^2.8.17", - "@types/express": "^5.0.0", - "@types/multer": "^1.4.12", - "@types/node": "^22.10.5", - "tsx": "^4.19.2", - "typescript": "~5.6.2" - } -} diff --git a/server/routes/builds.ts b/server/routes/builds.ts deleted file mode 100644 index ea0823e..0000000 --- a/server/routes/builds.ts +++ /dev/null @@ -1,184 +0,0 @@ -import { Router } from "express"; -import multer from "multer"; -import { nanoid } from "nanoid"; -import { - getBuild, - insertBuild, - listBuilds, - toPublicBuild, - updateBuild, - type BuildStatus, -} from "../db/index.js"; -import { - getActionsRunUrl, - getReleaseAssets, - getWorkflowRun, - triggerBuildWorkflow, - uploadSiteZip, -} from "../services/github.js"; -import { - normalizeAppIdentifier, - slugifyIdentifier, - validateChineseAppName, - validateEnglishAppName, - validateZipBuffer, - ZipValidationError, -} from "../services/zip.js"; - -const upload = multer({ - storage: multer.memoryStorage(), - limits: { fileSize: 100 * 1024 * 1024 }, -}); - -const maxUploadMb = Number(process.env.MAX_UPLOAD_MB ?? "50"); -const maxUploadBytes = maxUploadMb * 1024 * 1024; - -export const buildsRouter = Router(); - -buildsRouter.get("/", (_req, res) => { - const builds = listBuilds().map(toPublicBuild); - res.json({ builds }); -}); - -buildsRouter.get("/:id", async (req, res) => { - const record = getBuild(req.params.id); - if (!record) { - res.status(404).json({ error: "Build not found" }); - return; - } - - const refreshed = await refreshBuildStatus(record); - res.json({ - ...toPublicBuild(refreshed), - actionsUrl: getActionsRunUrl(refreshed.workflow_run_id), - }); -}); - -buildsRouter.post("/", upload.single("file"), async (req, res) => { - try { - const appNameZh = validateChineseAppName( - String(req.body.appNameZh ?? req.body.appName ?? ""), - ); - const appNameEn = validateEnglishAppName( - String(req.body.appNameEn ?? ""), - ); - const identifierInput = String(req.body.identifier ?? "").trim(); - - if (!req.file) { - res.status(400).json({ error: "file is required" }); - return; - } - - if (!req.file.originalname.toLowerCase().endsWith(".zip")) { - res.status(400).json({ error: "Only .zip files are supported" }); - return; - } - - const { normalizedBuffer } = validateZipBuffer(req.file.buffer, maxUploadBytes); - const jobId = nanoid(10); - const slug = slugifyIdentifier(appNameEn) || jobId.toLowerCase(); - const appIdentifier = normalizeAppIdentifier( - identifierInput || `com.web2app.${slug}`, - ); - - insertBuild({ - id: jobId, - appName: appNameZh, - appNameEn, - appIdentifier, - }); - - await uploadSiteZip(jobId, normalizedBuffer); - updateBuild(jobId, { status: "queued" }); - - const workflowRunId = await triggerBuildWorkflow({ - jobId, - appName: appNameZh, - appNameEn, - appIdentifier, - }); - - updateBuild(jobId, { - workflow_run_id: workflowRunId, - status: "in_progress", - }); - - res.status(201).json({ - id: jobId, - status: "in_progress", - workflowRunId, - }); - } catch (error) { - if (error instanceof ZipValidationError) { - res.status(400).json({ error: error.message }); - return; - } - - console.error(error); - res.status(500).json({ - error: error instanceof Error ? error.message : "Failed to create build", - }); - } -}); - -async function refreshBuildStatus(record: ReturnType & object) { - if (!record.workflow_run_id) return record; - if (record.status === "completed" || record.status === "failed") { - return record; - } - - try { - const run = await getWorkflowRun(record.workflow_run_id); - - if (run.status === "queued") { - return updateBuild(record.id, { status: "queued" }) ?? record; - } - - if (run.status === "in_progress") { - return updateBuild(record.id, { status: "in_progress" }) ?? record; - } - - if (run.status === "completed") { - if (run.conclusion === "success") { - const assets = await getReleaseAssets(record.id); - return ( - updateBuild(record.id, { - status: "completed", - windows_url: assets.windowsUrl, - android_url: assets.androidUrl, - error: - assets.windowsUrl && assets.androidUrl - ? null - : "Build finished but release assets were not found yet", - }) ?? record - ); - } - - return ( - updateBuild(record.id, { - status: "failed", - error: `Workflow failed with conclusion: ${run.conclusion ?? "unknown"}`, - }) ?? record - ); - } - - return record; - } catch (error) { - return ( - updateBuild(record.id, { - status: "failed", - error: error instanceof Error ? error.message : "Status refresh failed", - }) ?? record - ); - } -} - -export function buildPublicMeta(record: ReturnType) { - if (!record) return null; - return { - ...toPublicBuild(record), - actionsUrl: getActionsRunUrl(record.workflow_run_id), - }; -} - -export type { BuildStatus }; diff --git a/server/services/github.ts b/server/services/github.ts deleted file mode 100644 index a436a80..0000000 --- a/server/services/github.ts +++ /dev/null @@ -1,169 +0,0 @@ -import "../load-env.js"; -import { Octokit } from "octokit"; - -function getGitHubConfig() { - return { - owner: (process.env.GITHUB_OWNER ?? "").trim(), - repo: (process.env.GITHUB_REPO ?? "").trim(), - token: (process.env.GITHUB_TOKEN ?? "").trim(), - }; -} - -function getOctokit(): Octokit { - const { owner, repo, token } = getGitHubConfig(); - if (!owner || !repo || !token) { - throw new Error( - "Missing GITHUB_OWNER, GITHUB_REPO, or GITHUB_TOKEN environment variables", - ); - } - return new Octokit({ auth: token }); -} - -export function getRepoInfo() { - const { owner, repo } = getGitHubConfig(); - return { owner, repo }; -} - -export async function uploadSiteZip(jobId: string, zipBuffer: Buffer): Promise { - const { owner, repo } = getGitHubConfig(); - const octokit = getOctokit(); - const path = `builds/${jobId}/site.zip`; - const content = zipBuffer.toString("base64"); - - try { - await octokit.rest.repos.createOrUpdateFileContents({ - owner, - repo, - path, - message: `chore: upload site for build ${jobId}`, - content, - }); - } catch (error: unknown) { - const status = (error as { status?: number }).status; - if (status !== 422) throw error; - - const existing = await octokit.rest.repos.getContent({ owner, repo, path }); - if (Array.isArray(existing.data) || existing.data.type !== "file") { - throw new Error(`Unexpected content at ${path}`); - } - - await octokit.rest.repos.createOrUpdateFileContents({ - owner, - repo, - path, - message: `chore: update site for build ${jobId}`, - content, - sha: existing.data.sha, - }); - } -} - -export async function triggerBuildWorkflow(input: { - jobId: string; - appName: string; - appNameEn: string; - appIdentifier: string; -}): Promise { - const { owner, repo } = getGitHubConfig(); - const octokit = getOctokit(); - - await octokit.rest.actions.createWorkflowDispatch({ - owner, - repo, - workflow_id: "build-app.yml", - ref: process.env.DEFAULT_BRANCH ?? "main", - inputs: { - job_id: input.jobId, - app_name: input.appName, - app_name_en: input.appNameEn, - app_identifier: input.appIdentifier, - }, - }); - - await sleep(3000); - - const since = new Date(Date.now() - 120_000).toISOString(); - const runs = await octokit.rest.actions.listWorkflowRuns({ - owner, - repo, - workflow_id: "build-app.yml", - event: "workflow_dispatch", - per_page: 10, - }); - - const run = runs.data.workflow_runs - .filter((item) => item.created_at >= since) - .sort( - (a, b) => - new Date(b.created_at).getTime() - new Date(a.created_at).getTime(), - )[0]; - - if (!run) { - throw new Error("Failed to locate workflow run after dispatch"); - } - - return run.id; -} - -export async function getWorkflowRun(runId: number) { - const { owner, repo } = getGitHubConfig(); - const octokit = getOctokit(); - const { data } = await octokit.rest.actions.getWorkflowRun({ - owner, - repo, - run_id: runId, - }); - return data; -} - -export async function getReleaseAssets(jobId: string): Promise<{ - windowsUrl: string | null; - androidUrl: string | null; -}> { - const { owner, repo } = getGitHubConfig(); - const octokit = getOctokit(); - const tag = `build-${jobId}`; - - try { - const { data: release } = await octokit.rest.repos.getReleaseByTag({ - owner, - repo, - tag, - }); - - let windowsUrl: string | null = null; - let androidUrl: string | null = null; - - for (const asset of release.assets) { - const name = asset.name.toLowerCase(); - if ( - !windowsUrl && - (name.endsWith(".exe") || - name.endsWith(".msi") || - name.includes("windows")) - ) { - windowsUrl = asset.browser_download_url; - } - if ( - !androidUrl && - (name.endsWith(".apk") || name.includes("android")) - ) { - androidUrl = asset.browser_download_url; - } - } - - return { windowsUrl, androidUrl }; - } catch { - return { windowsUrl: null, androidUrl: null }; - } -} - -export function getActionsRunUrl(runId: number | null): string | null { - const { owner, repo } = getGitHubConfig(); - if (!runId || !owner || !repo) return null; - return `https://github.com/${owner}/${repo}/actions/runs/${runId}`; -} - -function sleep(ms: number) { - return new Promise((resolve) => setTimeout(resolve, ms)); -} diff --git a/server/tsconfig.json b/server/tsconfig.json deleted file mode 100644 index 5d62b64..0000000 --- a/server/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "ESNext", - "moduleResolution": "bundler", - "outDir": "dist", - "rootDir": ".", - "strict": true, - "skipLibCheck": true, - "esModuleInterop": true, - "resolveJsonModule": true - }, - "include": ["./**/*.ts"], - "exclude": ["dist", "node_modules"] -} diff --git a/web/src/App.tsx b/web/src/App.tsx deleted file mode 100644 index 1cbae6e..0000000 --- a/web/src/App.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { Route, Routes } from "react-router-dom"; -import JobStatus from "./pages/JobStatus"; -import Upload from "./pages/Upload"; - -export default function App() { - return ( -
-
-
-

Web2App

-

静态网页转原生应用

-
-

上传 zip(含 index.html),自动构建 Windows 与 Android 安装包

-
-
- - } /> - } /> - -
-
- ); -} diff --git a/web/src/pages/JobStatus.tsx b/web/src/pages/JobStatus.tsx deleted file mode 100644 index a294014..0000000 --- a/web/src/pages/JobStatus.tsx +++ /dev/null @@ -1,124 +0,0 @@ -import { useEffect, useState } from "react"; -import { Link, useParams } from "react-router-dom"; -import { fetchBuild, statusLabel, type Build } from "../api"; - -export default function JobStatus() { - const { id } = useParams<{ id: string }>(); - const [build, setBuild] = useState(null); - const [error, setError] = useState(null); - - useEffect(() => { - if (!id) return; - - let cancelled = false; - - async function poll() { - try { - const data = await fetchBuild(id!); - if (cancelled) return; - setBuild(data); - setError(null); - - if (data.status === "completed" || data.status === "failed") { - return; - } - - window.setTimeout(poll, 5000); - } catch (err) { - if (cancelled) return; - setError(err instanceof Error ? err.message : "加载失败"); - window.setTimeout(poll, 5000); - } - } - - poll(); - return () => { - cancelled = true; - }; - }, [id]); - - if (!id) { - return

缺少任务 ID

; - } - - return ( -
-
-

构建任务

- 返回上传 -
- - {error ?

{error}

: null} - - {build ? ( - <> -
-
-
任务 ID
-
{build.id}
-
-
-
应用中文名
-
{build.appName}
-
-
-
应用英文名
-
{build.appNameEn}
-
-
-
Bundle ID
-
{build.appIdentifier}
-
-
-
状态
-
- - {statusLabel(build.status)} - -
-
-
- - {build.status === "completed" ? ( -
-

下载安装包

-
- {build.windowsUrl ? ( - - 下载 Windows 版 - - ) : ( - Windows 安装包尚未就绪 - )} - {build.androidUrl ? ( - - 下载 Android 版 - - ) : ( - Android 安装包尚未就绪 - )} -
-
- ) : null} - - {build.status === "failed" ? ( -
-

{build.error ?? "构建失败,请查看 GitHub Actions 日志。"}

- {build.actionsUrl ? ( - - 查看 Actions 日志 - - ) : null} -
- ) : null} - - {build.status !== "completed" && build.status !== "failed" ? ( -

正在轮询 GitHub Actions 状态,请稍候...

- ) : null} - - ) : ( -

加载任务信息...

- )} -
- ); -} diff --git a/web/src/pages/Upload.tsx b/web/src/pages/Upload.tsx deleted file mode 100644 index 0656414..0000000 --- a/web/src/pages/Upload.tsx +++ /dev/null @@ -1,95 +0,0 @@ -import { FormEvent, useState } from "react"; -import { useNavigate } from "react-router-dom"; -import { createBuild } from "../api"; - -export default function Upload() { - const navigate = useNavigate(); - const [appNameZh, setAppNameZh] = useState(""); - const [appNameEn, setAppNameEn] = useState(""); - const [identifier, setIdentifier] = useState(""); - const [file, setFile] = useState(null); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); - - async function onSubmit(event: FormEvent) { - event.preventDefault(); - if (!file) { - setError("请选择 zip 文件"); - return; - } - - setLoading(true); - setError(null); - - try { - const formData = new FormData(); - formData.append("file", file); - formData.append("appNameZh", appNameZh); - formData.append("appNameEn", appNameEn); - if (identifier.trim()) { - formData.append("identifier", identifier.trim()); - } - - const result = await createBuild(formData); - navigate(`/jobs/${result.id}`); - } catch (err) { - setError(err instanceof Error ? err.message : "上传失败"); - } finally { - setLoading(false); - } - } - - return ( -
-

上传静态站点

-

- 压缩包需包含 index.html,大小默认不超过 50MB。可选在 zip 根目录放置 logo.png 或 - favicon.ico 作为应用图标(优先 logo.png)。中文名用于界面展示,英文名用于安装包与 - Bundle ID 生成。 -

-
- - - - - {error ?

{error}

: null} - -
-
- ); -} diff --git a/web/src/styles.css b/web/src/styles.css deleted file mode 100644 index e338fea..0000000 --- a/web/src/styles.css +++ /dev/null @@ -1,195 +0,0 @@ -:root { - color-scheme: light dark; - font-family: Inter, Segoe UI, system-ui, sans-serif; - line-height: 1.5; - background: #0f172a; - color: #e2e8f0; -} - -* { - box-sizing: border-box; -} - -body { - margin: 0; - min-height: 100vh; - background: - radial-gradient(circle at top, rgba(56, 189, 248, 0.18), transparent 35%), - #0f172a; -} - -a { - color: #38bdf8; -} - -.app-shell { - max-width: 880px; - margin: 0 auto; - padding: 48px 20px 80px; -} - -.app-header { - margin-bottom: 32px; -} - -.eyebrow { - margin: 0 0 8px; - text-transform: uppercase; - letter-spacing: 0.12em; - font-size: 12px; - color: #94a3b8; -} - -.app-header h1 { - margin: 0 0 8px; - font-size: 2.4rem; -} - -.subtitle { - margin: 0; - color: #94a3b8; -} - -.card { - background: rgba(15, 23, 42, 0.82); - border: 1px solid rgba(148, 163, 184, 0.18); - border-radius: 20px; - padding: 28px; - backdrop-filter: blur(12px); - box-shadow: 0 20px 60px rgba(15, 23, 42, 0.35); -} - -.card h2, -.card h3 { - margin-top: 0; -} - -.form { - display: grid; - gap: 16px; -} - -label { - display: grid; - gap: 8px; - font-weight: 600; -} - -input[type="text"], -input[type="file"] { - width: 100%; - padding: 12px 14px; - border-radius: 12px; - border: 1px solid rgba(148, 163, 184, 0.25); - background: rgba(2, 6, 23, 0.65); - color: inherit; -} - -button, -.button { - display: inline-flex; - align-items: center; - justify-content: center; - padding: 12px 18px; - border-radius: 12px; - border: none; - background: linear-gradient(135deg, #0284c7, #2563eb); - color: white; - font-weight: 700; - text-decoration: none; - cursor: pointer; -} - -button:disabled { - opacity: 0.7; - cursor: not-allowed; -} - -.button.secondary { - background: linear-gradient(135deg, #059669, #047857); -} - -.hint, -.muted { - color: #94a3b8; -} - -.error { - color: #fca5a5; -} - -.error-box { - margin-top: 16px; - padding: 16px; - border-radius: 12px; - background: rgba(127, 29, 29, 0.25); - border: 1px solid rgba(248, 113, 113, 0.35); -} - -.status-header { - display: flex; - align-items: center; - justify-content: space-between; - gap: 12px; -} - -.meta { - display: grid; - gap: 12px; - margin: 20px 0; -} - -.meta div { - display: grid; - grid-template-columns: 120px 1fr; - gap: 12px; -} - -.meta dt { - color: #94a3b8; -} - -.meta dd { - margin: 0; -} - -.badge { - display: inline-flex; - padding: 4px 10px; - border-radius: 999px; - font-size: 0.875rem; - background: rgba(148, 163, 184, 0.18); -} - -.badge-completed { - background: rgba(34, 197, 94, 0.18); - color: #86efac; -} - -.badge-failed { - background: rgba(239, 68, 68, 0.18); - color: #fca5a5; -} - -.badge-in_progress, -.badge-queued, -.badge-pending { - background: rgba(56, 189, 248, 0.18); - color: #7dd3fc; -} - -.downloads { - margin-top: 24px; -} - -.download-actions { - display: flex; - flex-wrap: wrap; - gap: 12px; -} - -@media (max-width: 640px) { - .meta div { - grid-template-columns: 1fr; - } -} diff --git a/web/src/vite-env.d.ts b/web/src/vite-env.d.ts deleted file mode 100644 index 11f02fe..0000000 --- a/web/src/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/web/tsconfig.app.tsbuildinfo b/web/tsconfig.app.tsbuildinfo deleted file mode 100644 index fe607d2..0000000 --- a/web/tsconfig.app.tsbuildinfo +++ /dev/null @@ -1 +0,0 @@ -{"root":["./src/app.tsx","./src/api.ts","./src/main.tsx","./src/vite-env.d.ts","./src/pages/jobstatus.tsx","./src/pages/upload.tsx"],"version":"5.6.3"} \ No newline at end of file diff --git a/web/tsconfig.tsbuildinfo b/web/tsconfig.tsbuildinfo deleted file mode 100644 index ce7f1a7..0000000 --- a/web/tsconfig.tsbuildinfo +++ /dev/null @@ -1 +0,0 @@ -{"root":["./src/app.tsx","./src/api.ts","./src/main.tsx","./src/pages/jobstatus.tsx","./src/pages/upload.tsx"],"errors":true,"version":"5.6.3"} \ No newline at end of file diff --git a/web/vite.config.js b/web/vite.config.js deleted file mode 100644 index ef4f4ae..0000000 --- a/web/vite.config.js +++ /dev/null @@ -1,14 +0,0 @@ -import { defineConfig } from "vite"; -import react from "@vitejs/plugin-react"; -export default defineConfig({ - plugins: [react()], - server: { - port: 5173, - proxy: { - "/api": { - target: "http://127.0.0.1:3001", - changeOrigin: true, - }, - }, - }, -}); diff --git a/server/db/schema.sql b/worker/migrations/0001_init.sql similarity index 100% rename from server/db/schema.sql rename to worker/migrations/0001_init.sql diff --git a/worker/migrations/0002_add_version.sql b/worker/migrations/0002_add_version.sql new file mode 100644 index 0000000..8652c4d --- /dev/null +++ b/worker/migrations/0002_add_version.sql @@ -0,0 +1 @@ +ALTER TABLE builds ADD COLUMN app_version TEXT NOT NULL DEFAULT '1.0.0'; diff --git a/worker/package.json b/worker/package.json new file mode 100644 index 0000000..298e4e0 --- /dev/null +++ b/worker/package.json @@ -0,0 +1,13 @@ +{ + "name": "web2app-worker", + "private": true, + "version": "0.1.0", + "type": "module", + "dependencies": { + "fflate": "^0.8.2", + "nanoid": "^5.0.9" + }, + "devDependencies": { + "@cloudflare/workers-types": "^4.20241127.0" + } +} diff --git a/worker/src/db/builds.ts b/worker/src/db/builds.ts new file mode 100644 index 0000000..4062074 --- /dev/null +++ b/worker/src/db/builds.ts @@ -0,0 +1,128 @@ +import type { Env } from "../env"; + +export type BuildStatus = + | "pending" + | "queued" + | "in_progress" + | "completed" + | "failed"; + +export interface BuildRecord { + id: string; + app_name: string; + app_name_en: string; + app_identifier: string; + app_version: string; + status: BuildStatus; + workflow_run_id: number | null; + windows_url: string | null; + android_url: string | null; + error: string | null; + created_at: string; + updated_at: string; +} + +export async function insertBuild( + env: Env, + record: { + id: string; + appName: string; + appNameEn: string; + appIdentifier: string; + appVersion: string; + }, +): Promise { + await env.DB.prepare( + `INSERT INTO builds (id, app_name, app_name_en, app_identifier, app_version, status) + VALUES (?, ?, ?, ?, ?, 'pending')`, + ) + .bind( + record.id, + record.appName, + record.appNameEn, + record.appIdentifier, + record.appVersion, + ) + .run(); + + const row = await getBuild(env, record.id); + if (!row) throw new Error("Failed to insert build"); + return row; +} + +export async function getBuild( + env: Env, + id: string, +): Promise { + const row = await env.DB.prepare("SELECT * FROM builds WHERE id = ?") + .bind(id) + .first(); + return row ?? null; +} + +export async function listBuilds( + env: Env, + limit = 20, +): Promise { + const { results } = await env.DB.prepare( + "SELECT * FROM builds ORDER BY created_at DESC LIMIT ?", + ) + .bind(limit) + .all(); + return results ?? []; +} + +export async function updateBuild( + env: Env, + id: string, + patch: Partial< + Pick< + BuildRecord, + | "status" + | "workflow_run_id" + | "windows_url" + | "android_url" + | "error" + > + >, +): Promise { + const fields: string[] = []; + const values: unknown[] = []; + + for (const [key, value] of Object.entries(patch)) { + if (value !== undefined) { + fields.push(`${key} = ?`); + values.push(value); + } + } + + if (fields.length === 0) return getBuild(env, id); + + fields.push("updated_at = datetime('now')"); + values.push(id); + + await env.DB.prepare( + `UPDATE builds SET ${fields.join(", ")} WHERE id = ?`, + ) + .bind(...values) + .run(); + + return getBuild(env, id); +} + +export function toPublicBuild(record: BuildRecord) { + return { + id: record.id, + appName: record.app_name, + appNameEn: record.app_name_en || record.app_name, + appIdentifier: record.app_identifier, + appVersion: record.app_version || "1.0.0", + status: record.status, + workflowRunId: record.workflow_run_id, + windowsUrl: record.windows_url, + androidUrl: record.android_url, + error: record.error, + createdAt: record.created_at, + updatedAt: record.updated_at, + }; +} diff --git a/worker/src/env.d.ts b/worker/src/env.d.ts new file mode 100644 index 0000000..ebda5a0 --- /dev/null +++ b/worker/src/env.d.ts @@ -0,0 +1,9 @@ +export interface Env { + DB: D1Database; + ASSETS: Fetcher; + GITHUB_TOKEN: string; + GITHUB_OWNER: string; + GITHUB_REPO: string; + DEFAULT_BRANCH?: string; + MAX_UPLOAD_MB?: string; +} diff --git a/worker/src/index.ts b/worker/src/index.ts new file mode 100644 index 0000000..814c0e1 --- /dev/null +++ b/worker/src/index.ts @@ -0,0 +1,19 @@ +import type { Env } from "./env"; +import { handleBuildsRequest } from "./routes/builds"; +import { jsonResponse } from "./lib/response"; + +export default { + async fetch(request: Request, env: Env): Promise { + const url = new URL(request.url); + + if (url.pathname === "/api/health") { + return jsonResponse({ ok: true }); + } + + if (url.pathname.startsWith("/api/builds")) { + return handleBuildsRequest(request, env, url); + } + + return env.ASSETS.fetch(request); + }, +}; diff --git a/worker/src/lib/response.ts b/worker/src/lib/response.ts new file mode 100644 index 0000000..7e97438 --- /dev/null +++ b/worker/src/lib/response.ts @@ -0,0 +1,17 @@ +export function jsonResponse( + data: unknown, + status = 200, + headers?: Record, +): Response { + return new Response(JSON.stringify(data), { + status, + headers: { + "Content-Type": "application/json", + ...headers, + }, + }); +} + +export function errorResponse(message: string, status: number): Response { + return jsonResponse({ error: message }, status); +} diff --git a/worker/src/routes/builds.ts b/worker/src/routes/builds.ts new file mode 100644 index 0000000..099e2f5 --- /dev/null +++ b/worker/src/routes/builds.ts @@ -0,0 +1,226 @@ +import { nanoid } from "nanoid"; +import type { Env } from "../env"; +import { + getBuild, + insertBuild, + listBuilds, + toPublicBuild, + updateBuild, + type BuildRecord, +} from "../db/builds"; +import { errorResponse, jsonResponse } from "../lib/response"; +import { + getActionsRunUrl, + getReleaseAssets, + getWorkflowRun, + triggerBuildWorkflow, + uploadBuildFile, + uploadSiteZip, +} from "../services/github"; +import { IconValidationError, resolveIconUpload } from "../services/icon"; +import { + validateAppVersion, + VersionValidationError, +} from "../services/version"; +import { + normalizeAppIdentifier, + slugifyIdentifier, + validateChineseAppName, + validateEnglishAppName, + validateZipBuffer, + ZipValidationError, +} from "../services/zip"; + +function maxUploadBytes(env: Env): number { + const mb = Number(env.MAX_UPLOAD_MB ?? "50"); + return mb * 1024 * 1024; +} + +export async function handleBuildsRequest( + request: Request, + env: Env, + url: URL, +): Promise { + const path = url.pathname; + + if (path === "/api/builds" && request.method === "GET") { + const builds = (await listBuilds(env)).map(toPublicBuild); + return jsonResponse({ builds }); + } + + const match = path.match(/^\/api\/builds\/([^/]+)$/); + if (match) { + const id = match[1]; + + if (request.method === "GET") { + const record = await getBuild(env, id); + if (!record) { + return errorResponse("Build not found", 404); + } + + const refreshed = await refreshBuildStatus(env, record); + return jsonResponse({ + ...toPublicBuild(refreshed), + actionsUrl: getActionsRunUrl(env, refreshed.workflow_run_id), + }); + } + + return errorResponse("Method not allowed", 405); + } + + if (path === "/api/builds" && request.method === "POST") { + return createBuild(request, env); + } + + return errorResponse("Not found", 404); +} + +async function createBuild(request: Request, env: Env): Promise { + try { + const formData = await request.formData(); + const appNameZh = validateChineseAppName( + String(formData.get("appNameZh") ?? formData.get("appName") ?? ""), + ); + const appNameEn = validateEnglishAppName( + String(formData.get("appNameEn") ?? ""), + ); + const identifierInput = String(formData.get("identifier") ?? "").trim(); + const appVersion = validateAppVersion( + String(formData.get("appVersion") ?? ""), + ); + + const file = formData.get("file"); + if (!(file instanceof File)) { + return errorResponse("file is required", 400); + } + + if (!file.name.toLowerCase().endsWith(".zip")) { + return errorResponse("Only .zip files are supported", 400); + } + + const buffer = new Uint8Array(await file.arrayBuffer()); + const { normalizedBuffer } = validateZipBuffer(buffer, maxUploadBytes(env)); + const jobId = nanoid(10); + const slug = slugifyIdentifier(appNameEn) || jobId.toLowerCase(); + const appIdentifier = normalizeAppIdentifier( + identifierInput || `com.web2app.${slug}`, + ); + + await insertBuild(env, { + id: jobId, + appName: appNameZh, + appNameEn, + appIdentifier, + appVersion, + }); + + await uploadSiteZip(env, jobId, normalizedBuffer); + await uploadBuildFile( + env, + jobId, + "version.txt", + new TextEncoder().encode(appVersion), + ); + + const iconFile = formData.get("icon"); + if (iconFile instanceof File && iconFile.size > 0) { + const iconBuffer = new Uint8Array(await iconFile.arrayBuffer()); + const { repoPath } = resolveIconUpload(iconFile, iconBuffer); + await uploadBuildFile(env, jobId, repoPath, iconBuffer); + } + + await updateBuild(env, jobId, { status: "queued" }); + + const workflowRunId = await triggerBuildWorkflow(env, { + jobId, + appName: appNameZh, + appNameEn, + appIdentifier, + }); + + await updateBuild(env, jobId, { + workflow_run_id: workflowRunId, + status: "in_progress", + }); + + return jsonResponse( + { + id: jobId, + status: "in_progress", + workflowRunId, + }, + 201, + ); + } catch (error) { + if ( + error instanceof ZipValidationError || + error instanceof VersionValidationError || + error instanceof IconValidationError + ) { + return errorResponse(error.message, 400); + } + + console.error(error); + return errorResponse( + error instanceof Error ? error.message : "Failed to create build", + 500, + ); + } +} + +async function refreshBuildStatus( + env: Env, + record: BuildRecord, +): Promise { + if (!record.workflow_run_id) return record; + if (record.status === "completed" || record.status === "failed") { + return record; + } + + try { + const run = await getWorkflowRun(env, record.workflow_run_id); + + if (run.status === "queued") { + return (await updateBuild(env, record.id, { status: "queued" })) ?? record; + } + + if (run.status === "in_progress") { + return ( + (await updateBuild(env, record.id, { status: "in_progress" })) ?? record + ); + } + + if (run.status === "completed") { + if (run.conclusion === "success") { + const assets = await getReleaseAssets(env, record.id); + return ( + (await updateBuild(env, record.id, { + status: "completed", + windows_url: assets.windowsUrl, + android_url: assets.androidUrl, + error: + assets.windowsUrl && assets.androidUrl + ? null + : "Build finished but release assets were not found yet", + })) ?? record + ); + } + + return ( + (await updateBuild(env, record.id, { + status: "failed", + error: `Workflow failed with conclusion: ${run.conclusion ?? "unknown"}`, + })) ?? record + ); + } + + return record; + } catch (error) { + return ( + (await updateBuild(env, record.id, { + status: "failed", + error: error instanceof Error ? error.message : "Status refresh failed", + })) ?? record + ); + } +} diff --git a/worker/src/services/github.ts b/worker/src/services/github.ts new file mode 100644 index 0000000..cd20065 --- /dev/null +++ b/worker/src/services/github.ts @@ -0,0 +1,252 @@ +import type { Env } from "../env"; + +function getGitHubConfig(env: Env) { + return { + owner: (env.GITHUB_OWNER ?? "").trim(), + repo: (env.GITHUB_REPO ?? "").trim(), + token: (env.GITHUB_TOKEN ?? "").trim(), + branch: (env.DEFAULT_BRANCH ?? "main").trim(), + }; +} + +function assertGitHubConfig(env: Env) { + const { owner, repo, token } = getGitHubConfig(env); + if (!owner || !repo || !token) { + throw new Error( + "Missing GITHUB_OWNER, GITHUB_REPO, or GITHUB_TOKEN configuration", + ); + } + return { owner, repo, token }; +} + +async function githubFetch( + env: Env, + path: string, + init?: RequestInit, +): Promise { + const { token } = assertGitHubConfig(env); + return fetch(`https://api.github.com${path}`, { + ...init, + headers: { + Accept: "application/vnd.github+json", + Authorization: `Bearer ${token}`, + "X-GitHub-Api-Version": "2022-11-28", + "User-Agent": "web2app-worker", + ...(init?.headers ?? {}), + }, + }); +} + +function bytesToBase64(bytes: Uint8Array): string { + let binary = ""; + const chunk = 0x8000; + for (let i = 0; i < bytes.length; i += chunk) { + binary += String.fromCharCode(...bytes.subarray(i, i + chunk)); + } + return btoa(binary); +} + +export async function uploadBuildFile( + env: Env, + jobId: string, + relativePath: string, + fileBuffer: Uint8Array, +): Promise { + const { owner, repo } = assertGitHubConfig(env); + const path = `builds/${jobId}/${relativePath}`; + const content = bytesToBase64(fileBuffer); + + const put = async (sha?: string) => { + const body: Record = { + message: sha + ? `chore: update ${relativePath} for build ${jobId}` + : `chore: upload ${relativePath} for build ${jobId}`, + content, + }; + if (sha) body.sha = sha; + + return githubFetch(env, `/repos/${owner}/${repo}/contents/${path}`, { + method: "PUT", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(body), + }); + }; + + let response = await put(); + if (response.status === 422) { + const getResponse = await githubFetch( + env, + `/repos/${owner}/${repo}/contents/${path}`, + ); + if (!getResponse.ok) { + const text = await getResponse.text(); + throw new Error(`GitHub get content failed (${getResponse.status}): ${text}`); + } + + const existing = (await getResponse.json()) as { + sha?: string; + type?: string; + }; + if (!existing.sha || existing.type !== "file") { + throw new Error(`Unexpected content at ${path}`); + } + + response = await put(existing.sha); + } + + if (!response.ok) { + const text = await response.text(); + throw new Error(`GitHub upload failed (${response.status}): ${text}`); + } +} + +export async function uploadSiteZip( + env: Env, + jobId: string, + zipBuffer: Uint8Array, +): Promise { + return uploadBuildFile(env, jobId, "site.zip", zipBuffer); +} + +export async function triggerBuildWorkflow( + env: Env, + input: { + jobId: string; + appName: string; + appNameEn: string; + appIdentifier: string; + }, +): Promise { + const { owner, repo, branch } = getGitHubConfig(env); + assertGitHubConfig(env); + + const dispatchResponse = await githubFetch( + env, + `/repos/${owner}/${repo}/actions/workflows/build-app.yml/dispatches`, + { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + ref: branch, + inputs: { + job_id: input.jobId, + app_name: input.appName, + app_name_en: input.appNameEn, + app_identifier: input.appIdentifier, + }, + }), + }, + ); + + if (!dispatchResponse.ok) { + const text = await dispatchResponse.text(); + throw new Error( + `Workflow dispatch failed (${dispatchResponse.status}): ${text}`, + ); + } + + await sleep(3000); + + const since = new Date(Date.now() - 120_000).toISOString(); + const runsResponse = await githubFetch( + env, + `/repos/${owner}/${repo}/actions/workflows/build-app.yml/runs?event=workflow_dispatch&per_page=10`, + ); + + if (!runsResponse.ok) { + const text = await runsResponse.text(); + throw new Error(`Failed to list workflow runs: ${text}`); + } + + const runsData = (await runsResponse.json()) as { + workflow_runs: Array<{ id: number; created_at: string }>; + }; + + const run = runsData.workflow_runs + .filter((item) => item.created_at >= since) + .sort( + (a, b) => + new Date(b.created_at).getTime() - new Date(a.created_at).getTime(), + )[0]; + + if (!run) { + throw new Error("Failed to locate workflow run after dispatch"); + } + + return run.id; +} + +export async function getWorkflowRun(env: Env, runId: number) { + const { owner, repo } = assertGitHubConfig(env); + const response = await githubFetch( + env, + `/repos/${owner}/${repo}/actions/runs/${runId}`, + ); + + if (!response.ok) { + const text = await response.text(); + throw new Error(`Failed to get workflow run: ${text}`); + } + + return (await response.json()) as { + status: string; + conclusion: string | null; + }; +} + +export async function getReleaseAssets( + env: Env, + jobId: string, +): Promise<{ + windowsUrl: string | null; + androidUrl: string | null; +}> { + const { owner, repo } = assertGitHubConfig(env); + const tag = `build-${jobId}`; + + const response = await githubFetch( + env, + `/repos/${owner}/${repo}/releases/tags/${encodeURIComponent(tag)}`, + ); + + if (!response.ok) { + return { windowsUrl: null, androidUrl: null }; + } + + const release = (await response.json()) as { + assets: Array<{ name: string; browser_download_url: string }>; + }; + + let windowsUrl: string | null = null; + let androidUrl: string | null = null; + + for (const asset of release.assets) { + const name = asset.name.toLowerCase(); + if ( + !windowsUrl && + (name.endsWith(".exe") || + name.endsWith(".msi") || + name.includes("windows")) + ) { + windowsUrl = asset.browser_download_url; + } + if ( + !androidUrl && + (name.endsWith(".apk") || name.includes("android")) + ) { + androidUrl = asset.browser_download_url; + } + } + + return { windowsUrl, androidUrl }; +} + +export function getActionsRunUrl(env: Env, runId: number | null): string | null { + const { owner, repo } = getGitHubConfig(env); + if (!runId || !owner || !repo) return null; + return `https://github.com/${owner}/${repo}/actions/runs/${runId}`; +} + +function sleep(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} diff --git a/worker/src/services/icon.ts b/worker/src/services/icon.ts new file mode 100644 index 0000000..336eacf --- /dev/null +++ b/worker/src/services/icon.ts @@ -0,0 +1,50 @@ +export class IconValidationError extends Error { + constructor(message: string) { + super(message); + this.name = "IconValidationError"; + } +} + +const MAX_ICON_BYTES = 2 * 1024 * 1024; + +const ALLOWED_TYPES = new Set([ + "image/png", + "image/jpeg", + "image/x-icon", + "image/vnd.microsoft.icon", +]); + +const ALLOWED_EXT = new Set([".png", ".jpg", ".jpeg", ".ico"]); + +export function resolveIconUpload( + file: File, + buffer: Uint8Array, +): { repoPath: string; fileName: string } { + if (buffer.length > MAX_ICON_BYTES) { + throw new IconValidationError("图标文件不能超过 2MB"); + } + + const ext = pathExt(file.name).toLowerCase(); + if (!ALLOWED_EXT.has(ext)) { + throw new IconValidationError("图标仅支持 PNG、JPG、ICO 格式"); + } + + const type = file.type.toLowerCase(); + if (type && !ALLOWED_TYPES.has(type) && type !== "application/octet-stream") { + throw new IconValidationError("不支持的图标 MIME 类型"); + } + + if (ext === ".ico") { + return { repoPath: "favicon.ico", fileName: "favicon.ico" }; + } + if (ext === ".jpg" || ext === ".jpeg") { + return { repoPath: "logo.jpg", fileName: "logo.jpg" }; + } + + return { repoPath: "logo.png", fileName: "logo.png" }; +} + +function pathExt(name: string): string { + const i = name.lastIndexOf("."); + return i >= 0 ? name.slice(i) : ""; +} diff --git a/worker/src/services/version.ts b/worker/src/services/version.ts new file mode 100644 index 0000000..3b767a4 --- /dev/null +++ b/worker/src/services/version.ts @@ -0,0 +1,25 @@ +export class VersionValidationError extends Error { + constructor(message: string) { + super(message); + this.name = "VersionValidationError"; + } +} + +/** 当前日期版本,格式如 2026.5.29(月、日不补零) */ +export function getDefaultAppVersion(date = new Date()): string { + return `${date.getFullYear()}.${date.getMonth() + 1}.${date.getDate()}`; +} + +export function validateAppVersion(input: string): string { + const value = input.trim() || getDefaultAppVersion(); + if (!/^\d{4}\.\d{1,2}\.\d{1,2}$/.test(value)) { + throw new VersionValidationError( + "版本号格式应为 YYYY.M.D,例如 2026.5.29", + ); + } + const [, month, day] = value.split(".").map(Number); + if (month < 1 || month > 12 || day < 1 || day > 31) { + throw new VersionValidationError("版本号中的月或日无效"); + } + return value; +} diff --git a/server/services/zip.ts b/worker/src/services/zip.ts similarity index 60% rename from server/services/zip.ts rename to worker/src/services/zip.ts index 92fb8d3..3085335 100644 --- a/server/services/zip.ts +++ b/worker/src/services/zip.ts @@ -1,7 +1,4 @@ -import AdmZip from "adm-zip"; -import fs from "node:fs"; -import os from "node:os"; -import path from "node:path"; +import { unzipSync, zipSync } from "fflate"; export class ZipValidationError extends Error { constructor(message: string) { @@ -11,29 +8,31 @@ export class ZipValidationError extends Error { } export function validateZipBuffer( - buffer: Buffer, + buffer: Uint8Array, maxBytes: number, -): { normalizedBuffer: Buffer } { +): { normalizedBuffer: Uint8Array } { if (buffer.length > maxBytes) { throw new ZipValidationError( `Zip file exceeds ${Math.floor(maxBytes / (1024 * 1024))}MB limit`, ); } - let zip: AdmZip; + let files: Record; try { - zip = new AdmZip(buffer); + files = unzipSync(buffer); } catch { throw new ZipValidationError("Invalid zip archive"); } - const entries = zip.getEntries().filter((entry) => !entry.isDirectory); + const entries = Object.keys(files).filter( + (key) => !key.endsWith("/") && files[key].length > 0, + ); if (entries.length === 0) { throw new ZipValidationError("Zip archive is empty"); } const indexEntry = entries.find((entry) => { - const normalized = entry.entryName.replace(/\\/g, "/"); + const normalized = entry.replace(/\\/g, "/"); if (normalized === "index.html") return true; const parts = normalized.split("/"); return parts.length === 2 && parts[1] === "index.html"; @@ -45,52 +44,67 @@ export function validateZipBuffer( ); } - const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "web2app-")); - try { - zip.extractAllTo(tmpDir, true); - const rootIndex = path.join(tmpDir, "index.html"); - if (!fs.existsSync(rootIndex)) { - const subdirs = fs - .readdirSync(tmpDir, { withFileTypes: true }) - .filter((d) => d.isDirectory()); - if (subdirs.length !== 1) { - throw new ZipValidationError( - "index.html must be at zip root or inside exactly one folder", - ); - } - const nestedRoot = path.join(tmpDir, subdirs[0].name); - flattenDirectory(nestedRoot, tmpDir); - } - const normalizedZip = new AdmZip(); - addDirectoryToZip(normalizedZip, tmpDir, ""); - return { normalizedBuffer: normalizedZip.toBuffer() }; - } finally { - fs.rmSync(tmpDir, { recursive: true, force: true }); - } + const normalized = normalizeZipFiles(files); + return { normalizedBuffer: zipSync(normalized) }; } -function flattenDirectory(sourceDir: string, targetDir: string) { - for (const entry of fs.readdirSync(sourceDir, { withFileTypes: true })) { - const from = path.join(sourceDir, entry.name); - const to = path.join(targetDir, entry.name); - if (entry.isDirectory()) { - fs.cpSync(from, to, { recursive: true }); - } else { - fs.copyFileSync(from, to); - } +function normalizeZipFiles( + files: Record, +): Record { + const map: Record = {}; + for (const [key, data] of Object.entries(files)) { + const path = key.replace(/\\/g, "/").replace(/^\.\//, ""); + if (path.endsWith("/")) continue; + map[path] = data; } -} -function addDirectoryToZip(zip: AdmZip, dir: string, prefix: string) { - for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { - const fullPath = path.join(dir, entry.name); - const entryName = prefix ? `${prefix}/${entry.name}` : entry.name; - if (entry.isDirectory()) { - addDirectoryToZip(zip, fullPath, entryName); - } else { - zip.addFile(entryName, fs.readFileSync(fullPath)); - } + if (map["index.html"]) { + return map; } + + const keys = Object.keys(map); + const indexKey = keys.find((k) => { + const parts = k.split("/"); + return parts.length === 2 && parts[1] === "index.html"; + }); + + if (!indexKey) { + throw new ZipValidationError( + "index.html must be at zip root or inside exactly one folder", + ); + } + + const folder = indexKey.split("/")[0]; + const topDirs = new Set( + keys.map((k) => k.split("/")[0]).filter(Boolean), + ); + + if (topDirs.size !== 1 || !topDirs.has(folder)) { + throw new ZipValidationError( + "index.html must be at zip root or inside exactly one folder", + ); + } + + const flat: Record = {}; + const prefix = `${folder}/`; + for (const [key, data] of Object.entries(map)) { + if (!key.startsWith(prefix)) { + throw new ZipValidationError( + "index.html must be at zip root or inside exactly one folder", + ); + } + const rel = key.slice(prefix.length); + if (!rel) continue; + flat[rel] = data; + } + + if (!flat["index.html"]) { + throw new ZipValidationError( + "index.html must be at zip root or inside exactly one folder", + ); + } + + return flat; } const JAVA_RESERVED_SEGMENTS = new Set([ diff --git a/worker/tsconfig.json b/worker/tsconfig.json new file mode 100644 index 0000000..071260e --- /dev/null +++ b/worker/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "Bundler", + "lib": ["ES2022"], + "types": ["@cloudflare/workers-types"], + "strict": true, + "skipLibCheck": true, + "noEmit": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts"] +} diff --git a/wrangler.toml b/wrangler.toml new file mode 100644 index 0000000..241a97f --- /dev/null +++ b/wrangler.toml @@ -0,0 +1,20 @@ +name = "web2app" +main = "worker/src/index.ts" +compatibility_date = "2024-11-01" + +[assets] +directory = "./frontend/dist" +not_found_handling = "single-page-application" + +# 运行 `wrangler d1 create web2app` 后将输出的 database_id 替换下方占位符 +[[d1_databases]] +binding = "DB" +database_name = "web2app" +database_id = "e45bfa13-525b-465c-8dbb-b1a716751b44" +migrations_dir = "worker/migrations" + +[vars] +DEFAULT_BRANCH = "main" +MAX_UPLOAD_MB = "50" +GITHUB_OWNER = "shumengya" +GITHUB_REPO = "Web2App" \ No newline at end of file