diff --git a/.gitea/workflows/app.yml b/.gitea/workflows/app.yml
new file mode 100644
index 0000000..0d3ee7a
--- /dev/null
+++ b/.gitea/workflows/app.yml
@@ -0,0 +1,67 @@
+name: Unified application CI and deployment
+on:
+ pull_request:
+ branches: [main]
+ paths:
+ - 'apps/waterfall-wiki/**'
+ - 'packages/brand/**'
+ - 'scripts/**'
+ - 'Dockerfile'
+ - '.dockerignore'
+ - 'compose.yml'
+ - 'pnpm-workspace.yaml'
+ - '.gitea/workflows/app.yml'
+ push:
+ branches: [main]
+ paths:
+ - 'apps/waterfall-wiki/**'
+ - 'packages/brand/**'
+ - 'scripts/**'
+ - 'Dockerfile'
+ - '.dockerignore'
+ - 'compose.yml'
+ - 'pnpm-workspace.yaml'
+ - '.gitea/workflows/app.yml'
+concurrency:
+ group: unified-app-${{ gitea.event.pull_request.number || gitea.ref }}
+ cancel-in-progress: false
+jobs:
+ verify-and-release:
+ runs-on: ces-control
+ timeout-minutes: 60
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ - name: Check scripts and content contracts
+ run: |
+ git diff --check HEAD^ HEAD
+ for script in scripts/*.sh; do bash -n "$script"; done
+ node scripts/check-studio-contracts.mjs
+ node --check scripts/verify-studio-visual.cjs
+ node --check apps/waterfall-wiki/scripts/infinite-canvas-smoke.cjs
+ - name: Build and verify the unified application once
+ run: |
+ docker build --target integration -t "waterfall-wiki-tests:${{ gitea.sha }}" .
+ docker build --target runtime -t "waterfall-wiki:${{ gitea.sha }}" .
+ - name: Verify candidate using persistent test infrastructure
+ env:
+ WATERFALL_WIKI_IMAGE: waterfall-wiki:${{ gitea.sha }}
+ WATERFALL_WIKI_TEST_IMAGE: waterfall-wiki-tests:${{ gitea.sha }}
+ GITEA_RUN_ID: ${{ gitea.run_id }}
+ run: bash scripts/integration.sh
+ - name: Deploy unified Web and worker; verify production
+ if: gitea.event_name == 'push' && gitea.ref == 'refs/heads/main'
+ run: bash scripts/deploy.sh "${{ gitea.sha }}"
+ - name: Save production acceptance evidence
+ id: evidence
+ if: always() && gitea.event_name == 'push'
+ uses: actions/upload-artifact@v3
+ with:
+ name: unified-production-acceptance
+ path: artifacts/studio-acceptance/
+ if-no-files-found: ignore
+ retention-days: 7
+ - name: Remove uploaded local evidence
+ if: always() && steps.evidence.outcome == 'success'
+ run: rm -rf artifacts/studio-acceptance
diff --git a/.gitea/workflows/brand.yml b/.gitea/workflows/brand.yml
deleted file mode 100644
index 436bc88..0000000
--- a/.gitea/workflows/brand.yml
+++ /dev/null
@@ -1,29 +0,0 @@
-name: Endoleap brand checks
-on:
- pull_request:
- branches: [main]
- paths:
- - '.dockerignore'
- - 'packages/brand/**'
- - 'pnpm-workspace.yaml'
- - 'package.json'
- - 'AGENTS.md'
- - '.gitea/workflows/brand.yml'
- push:
- branches: [main]
- paths:
- - '.dockerignore'
- - 'packages/brand/**'
- - 'pnpm-workspace.yaml'
- - '.gitea/workflows/brand.yml'
-concurrency:
- group: brand-${{ gitea.event.pull_request.number || gitea.ref }}
- cancel-in-progress: true
-jobs:
- verify:
- runs-on: ces-control
- timeout-minutes: 20
- steps:
- - uses: actions/checkout@v4
- - name: Verify brand assets, Tailwind compilation and typed exports in Docker
- run: docker build -f packages/brand/Dockerfile -t "endoleap-brand-check:${{ gitea.sha }}" .
diff --git a/.gitea/workflows/creative-workspace.yml b/.gitea/workflows/creative-workspace.yml
deleted file mode 100644
index cbb2b86..0000000
--- a/.gitea/workflows/creative-workspace.yml
+++ /dev/null
@@ -1,84 +0,0 @@
-name: creative workspace review checks
-on:
- pull_request:
- branches: [main]
- paths:
- - '.dockerignore'
- - 'Dockerfile'
- - 'pnpm-workspace.yaml'
- - 'apps/studio/**'
- - 'packages/brand/**'
- - 'apps/waterfall-wiki/**'
- - '.gitea/workflows/**'
- - 'scripts/*studio*'
- - 'compose.creative-review.yml'
- - 'scripts/integration.sh'
- - 'scripts/cleanup-integration.sh'
- - 'scripts/test-integration-cleanup.py'
- - 'scripts/cleanup-review-images.sh'
- - 'scripts/test-review-image-cleanup.py'
-concurrency:
- group: creative-workspace-${{ gitea.event.pull_request.number }}
- cancel-in-progress: true
-jobs:
- verify-deployed-canvas:
- runs-on: ces-control
- timeout-minutes: 15
- steps:
- - uses: actions/checkout@v4
- - name: Verify production acceptance against the designated deployed server
- run: |
- node --check scripts/verify-studio-visual.cjs
- node --check apps/studio/scripts/infinite-canvas-smoke.cjs
- bash -n scripts/verify-studio-production.sh
- bash scripts/verify-studio-production.sh
- - name: Save server acceptance evidence
- id: acceptance_evidence
- if: always()
- uses: actions/upload-artifact@v3
- with:
- name: studio-production-acceptance
- path: artifacts/studio-acceptance/
- if-no-files-found: ignore
- retention-days: 7
- - name: Remove temporary acceptance output after upload
- if: always() && steps.acceptance_evidence.outcome == 'success'
- run: rm -rf artifacts/studio-acceptance
- verify:
- runs-on: ces-control
- timeout-minutes: 60
- steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0
- - name: Check patch formatting
- run: |
- git diff --check HEAD^ HEAD
- bash -n scripts/integration.sh scripts/cleanup-integration.sh scripts/verify-studio-production.sh scripts/cleanup-review-images.sh
- node --check scripts/verify-studio-visual.cjs
- python3 scripts/test-integration-cleanup.py
- python3 scripts/test-review-image-cleanup.py
- node --test apps/waterfall-wiki/tests/brand-navigation.test.mjs
- - name: Verify Studio types, tests, build and smoke
- run: docker build -f apps/studio/Dockerfile -t "creative-studio-review:${{ gitea.sha }}" .
- - name: Build Wiki integration and runtime images
- run: |
- docker build --target integration -t "creative-wiki-tests:${{ gitea.sha }}" .
- docker build --target runtime -t "creative-wiki-review:${{ gitea.sha }}" .
- - name: Verify isolated PostgreSQL, S3 and browser integration
- env:
- STUDIO_REVIEW_IMAGE: creative-studio-review:${{ gitea.sha }}
- WATERFALL_WIKI_IMAGE: creative-wiki-review:${{ gitea.sha }}
- WATERFALL_WIKI_TEST_IMAGE: creative-wiki-tests:${{ gitea.sha }}
- GITEA_RUN_ID: ${{ gitea.run_id }}
- run: bash scripts/integration.sh
- - name: Clean this run disposable integration resources even after cancellation
- if: always()
- env:
- GITEA_RUN_ID: ${{ gitea.run_id }}
- run: bash scripts/cleanup-integration.sh
- - name: Remove this run disposable review image tags
- if: always()
- env:
- REVIEW_SHA: ${{ gitea.sha }}
- run: bash scripts/cleanup-review-images.sh
diff --git a/.gitea/workflows/waterfall-wiki.yml b/.gitea/workflows/waterfall-wiki.yml
deleted file mode 100644
index 9d10db1..0000000
--- a/.gitea/workflows/waterfall-wiki.yml
+++ /dev/null
@@ -1,73 +0,0 @@
-name: creative workspace CI and deployment
-on:
- push:
- branches: [main]
- paths:
- - '.dockerignore'
- - 'apps/waterfall-wiki/**'
- - 'apps/studio/**'
- - 'packages/brand/**'
- - 'scripts/*studio*'
- - 'content/studio-examples/**'
- - 'content/studio-tools/layouts-api.md'
- - '.gitea/workflows/waterfall-wiki.yml'
- - 'Dockerfile'
- - 'compose.yml'
- - 'scripts/deploy.sh'
- - 'scripts/wiki-image-lifecycle.py'
- - 'scripts/infra.sh'
- - 'scripts/auth-admin.sh'
- - 'scripts/integration.sh'
- - 'scripts/cleanup-integration.sh'
- - 'scripts/test-integration-cleanup.py'
- - 'pnpm-workspace.yaml'
-
-jobs:
- verify-and-deploy:
- if: gitea.ref == 'refs/heads/main' && gitea.event_name == 'push'
- runs-on: ces-control
- timeout-minutes: 60
- steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0
- - name: Check shared content and documentation contracts
- run: |
- python3 scripts/test-integration-cleanup.py
- bash -n scripts/integration.sh scripts/cleanup-integration.sh
- node scripts/check-studio-contracts.mjs
- node --check scripts/export-studio-series.cjs
- node --check scripts/save-studio-series.mjs
- bash -n scripts/publish-studio-guide.sh scripts/deliver-studio-series.sh
- - name: Build and verify Studio
- run: docker build -f apps/studio/Dockerfile -t "prompt-studio:${{ gitea.sha }}" .
- - name: Build, verify, deploy and retain wiki images
- env:
- RELEASE_SHA: ${{ gitea.sha }}
- run: |
- if [ "$(id -u)" -eq 0 ]; then
- python3 scripts/wiki-image-lifecycle.py ci --sha "$RELEASE_SHA"
- else
- sudo -n python3 scripts/wiki-image-lifecycle.py ci --sha "$RELEASE_SHA"
- fi
- - name: Release Studio after Wiki routes are deployed
- run: bash scripts/deploy-studio.sh "${{ gitea.sha }}"
- - name: Verify the deployed creative workspace
- run: bash scripts/verify-studio-production.sh
- - name: Save server acceptance evidence
- id: acceptance_evidence
- if: always()
- uses: actions/upload-artifact@v3
- with:
- name: studio-production-acceptance
- path: artifacts/studio-acceptance/
- if-no-files-found: ignore
- retention-days: 7
- - name: Remove temporary acceptance output after upload
- if: always() && steps.acceptance_evidence.outcome == 'success'
- run: rm -rf artifacts/studio-acceptance
- - name: Clean this run disposable integration resources even after cancellation
- if: always()
- env:
- GITEA_RUN_ID: ${{ gitea.run_id }}
- run: bash scripts/cleanup-integration.sh
diff --git a/Dockerfile b/Dockerfile
index 363449f..0b346ea 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -24,6 +24,7 @@ COPY apps/waterfall-wiki/ .
RUN pnpm typecheck && pnpm test && pnpm build && pnpm test:smoke
FROM build AS integration
+ENV VERIFY_CANVAS_UI=1
USER node
CMD ["npm", "run", "test:integration"]
diff --git a/README.md b/README.md
index 1b6a690..721a33e 100644
--- a/README.md
+++ b/README.md
@@ -55,7 +55,7 @@ Studio 负责交互式排版与无状态渲染,知识库负责教程、来源
| 路径 | 职责 |
| --- | --- |
| `apps/waterfall-wiki` | Next.js Pages Router 知识库、搜索、标签、媒体 API、认证与后台视频加工 |
-| `apps/studio` | 独立 Next.js 创作工具与封面渲染 API |
+| `apps/waterfall-wiki/src/studio` | 合并后的创作工具、排版渲染与编辑器模块 |
| `apps/python` | 按需运行的 PNG/视频导出 CLI,没有常驻网络服务 |
| `content` | 本地作者资料、教程及排版源图,不打入 Wiki 运行镜像 |
| `scripts` | CI 部署、运维、API 发布与作者工具 |
@@ -71,8 +71,8 @@ Studio 负责交互式排版与无状态渲染,知识库负责教程、来源
pnpm install
pnpm --dir apps/waterfall-wiki typecheck
pnpm --dir apps/waterfall-wiki test
-pnpm --dir apps/studio typecheck
-bash -n scripts/deploy.sh scripts/integration.sh scripts/deploy-studio.sh
+node scripts/check-studio-contracts.mjs
+for script in scripts/*.sh; do bash -n "$script"; done
```
完整集成测试只针对显式隔离的数据库、对象存储和生产容器运行,覆盖存储、视频加工、编辑冲突、真实搜索与引用、标签规则和登录保护。不要把生产存储配置拿来运行集成测试。
@@ -81,14 +81,14 @@ bash -n scripts/deploy.sh scripts/integration.sh scripts/deploy-studio.sh
## 部署与持久化
-Web 应用由 `waterfall-wiki.yml` 统一发布,两个应用的路径都能触发它:先检查并构建 Studio,再完成 Wiki 的类型检查、单元测试、生产构建、冒烟及隔离 PostgreSQL/S3 集成测试并部署 Wiki,随后部署 Studio,最后在指定服务器验收。顺序在同一个 ces-control 作业内保证,避免独立作业互相等待。PR 检查也运行隔离集成测试,但不部署。Python 检查仍由 `python.yml` 承担;文档与作者数据本身不触发应用部署。
+Web 应用由 `.gitea/workflows/app.yml` 统一验证与发布。Wiki 和 Studio 已合并成一个 Next.js 应用,一次编译、一个 Web 运行镜像,Web 与后台 worker 使用同一镜像。PostgreSQL/S3 基础服务长期运行,不在日常发布中重建。PR 验证候选版本但不部署;只有 main push 才更新生产。完整步骤见 [统一部署流程](docs/unified-deployment.md)。
| 服务 | 入口/端口 |
| --- | --- |
| `waterfall-wiki` | 公网 `18131`,也是 Studio 的统一入口 |
| PostgreSQL | `127.0.0.1:18132` |
| 对象存储 | `127.0.0.1:18133` |
-| Studio | `127.0.0.1:18134`;编辑器公网入口为 `/graphic`、`/infinite_canvas`,资源和 API 保留 `/studio` 代理 |
+| 编辑器 | 与知识站共享 `18131`;原生路由 `/graphic`、`/infinite_canvas`,历史 `/studio` 页面与 API 保留兼容 |
| Python | 无网络端口,按需运行 |
生产 Compose 项目仍为 `prompt`,部署根目录仍为 `/opt/prompt`。既有 `prompt_postgres_data`、`prompt_objects`、`prompt_auth_data` 卷与数据库身份保留;应用更名不会重新创建一套空存储。Compose 应用服务改为 `waterfall-wiki` 和 `waterfall-wiki-worker`,镜像参数为 `WATERFALL_WIKI_IMAGE` / `WATERFALL_WIKI_TEST_IMAGE`。
diff --git a/apps/studio/Dockerfile b/apps/studio/Dockerfile
deleted file mode 100644
index d73b6b4..0000000
--- a/apps/studio/Dockerfile
+++ /dev/null
@@ -1,25 +0,0 @@
-FROM node:24-bookworm-slim AS build
-WORKDIR /repo/apps/studio
-RUN corepack enable && corepack prepare pnpm@11.25.0 --activate
-COPY apps/studio/pnpm-lock.yaml ./
-COPY pnpm-workspace.yaml /repo/pnpm-workspace.yaml
-COPY packages/brand/package.json /repo/packages/brand/package.json
-COPY apps/studio/package.json ./
-RUN pnpm --filter @prompt/studio install --frozen-lockfile --fetch-timeout=300000 --network-concurrency=8
-# Brand source changes invalidate compilation, not dependency installation.
-COPY packages/brand/ /repo/packages/brand/
-COPY apps/studio/ .
-# Compare the two public parameter validators inside the isolated CI build.
-COPY apps/waterfall-wiki/src/lib/layout-parameters.ts /repo/apps/waterfall-wiki/src/lib/layout-parameters.ts
-COPY apps/waterfall-wiki/src/lib/series.ts /repo/apps/waterfall-wiki/src/lib/series.ts
-COPY apps/waterfall-wiki/src/lib/canvas-document.ts /repo/apps/waterfall-wiki/src/lib/canvas-document.ts
-RUN pnpm typecheck && pnpm test && pnpm build && pnpm test:smoke
-FROM node:24-bookworm-slim
-WORKDIR /app/apps/studio
-ENV NODE_ENV=production HOSTNAME=0.0.0.0 PORT=3000
-COPY --from=build --chown=node:node /repo/apps/studio/.next/standalone/ /app/
-COPY --from=build --chown=node:node /repo/apps/studio/.next/static/ ./.next/static/
-COPY --from=build --chown=node:node /repo/apps/studio/public/ ./public/
-USER node
-EXPOSE 3000
-CMD ["node", "server.js"]
diff --git a/apps/studio/next-env.d.ts b/apps/studio/next-env.d.ts
deleted file mode 100644
index 15849f6..0000000
--- a/apps/studio/next-env.d.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-///
-///
-import "./.next/types/routes.d.ts";
-import "./.next/types/root-params.d.ts";
-
-// NOTE: This file should not be edited
-// see https://nextjs.org/docs/pages/api-reference/config/typescript for more information.
diff --git a/apps/studio/next.config.ts b/apps/studio/next.config.ts
deleted file mode 100644
index 67416ad..0000000
--- a/apps/studio/next.config.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-import { resolve } from "node:path";
-import type { NextConfig } from "next";
-const config: NextConfig = { turbopack: { root: resolve(process.cwd(), "../..") }, basePath: "/studio", output: "standalone", outputFileTracingRoot: resolve(process.cwd(), "../.."), poweredByHeader: false };
-export default config;
diff --git a/apps/studio/package.json b/apps/studio/package.json
deleted file mode 100644
index 0b75aab..0000000
--- a/apps/studio/package.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "name": "@prompt/studio",
- "private": true,
- "scripts": {
- "dev": "pnpm brand:prepare && next dev -p 3001",
- "build": "pnpm brand:prepare && next build",
- "start": "next start",
- "typecheck": "next typegen && tsc --noEmit",
- "test": "node --test tests/*.test.mjs",
- "test:smoke": "node scripts/smoke.mjs",
- "brand:prepare": "node ../../packages/brand/scripts/prepare-app.mjs"
- },
- "dependencies": {
- "next": "16.4.2",
- "react": "19.3.1",
- "react-dom": "19.3.1",
- "lucide-react": "1.61.0",
- "@endoleap/brand": "workspace:*"
- },
- "devDependencies": {
- "@tailwindcss/postcss": "4.3.3",
- "@types/node": "24.19.2",
- "@types/react": "19.3.0",
- "@types/react-dom": "19.3.0",
- "tailwindcss": "4.3.3",
- "typescript": "5.9.3"
- },
- "packageManager": "pnpm@11.25.0"
-}
diff --git a/apps/studio/pnpm-lock.yaml b/apps/studio/pnpm-lock.yaml
deleted file mode 100644
index d65df4b..0000000
--- a/apps/studio/pnpm-lock.yaml
+++ /dev/null
@@ -1,1033 +0,0 @@
-lockfileVersion: '9.0'
-
-settings:
- autoInstallPeers: true
- excludeLinksFromLockfile: false
-
-importers:
-
- .:
- dependencies:
- '@endoleap/brand':
- specifier: workspace:*
- version: link:../../packages/brand
- lucide-react:
- specifier: 1.61.0
- version: 1.61.0(@types/react@19.3.0)(react@19.3.1)
- next:
- specifier: 16.4.2
- version: 16.4.2(@types/node@24.19.2)(react-dom@19.3.1(react@19.3.1))(react@19.3.1)
- react:
- specifier: 19.3.1
- version: 19.3.1
- react-dom:
- specifier: 19.3.1
- version: 19.3.1(react@19.3.1)
- devDependencies:
- '@tailwindcss/postcss':
- specifier: 4.3.3
- version: 4.3.3
- '@types/node':
- specifier: 24.19.2
- version: 24.19.2
- '@types/react':
- specifier: 19.3.0
- version: 19.3.0
- '@types/react-dom':
- specifier: 19.3.0
- version: 19.3.0(@types/react@19.3.0)
- tailwindcss:
- specifier: 4.3.3
- version: 4.3.3
- typescript:
- specifier: 5.9.3
- version: 5.9.3
-
-packages:
-
- '@alloc/quick-lru@5.3.0':
- resolution: {integrity: sha512-U4+70Pc5ZS9osnCBCE5Jha/ciHM+Yp+CNMNC/7HvYbNRk1Ldd+f7qO65W5qfhu/TCv+/ozljlXXe9Nj8419DMA==}
- engines: {node: '>=10'}
-
- '@emnapi/runtime@1.11.3':
- resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==}
-
- '@img/colour@1.1.0':
- resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==}
- engines: {node: '>=18'}
-
- '@img/sharp-darwin-arm64@0.35.5':
- resolution: {integrity: sha512-QRUlFQ0WxvdWyqqG/WtI3iupfD5rBzmCHXSdPsY91sAtVtTo7Q4cb6zOccZ3gqEqkr0f1As1ehLqmEpDsRf+lg==}
- engines: {node: '>=20.9.0'}
- cpu: [arm64]
- os: [darwin]
-
- '@img/sharp-darwin-x64@0.35.5':
- resolution: {integrity: sha512-+BR255RhDlpygUpOc/Jdt1nT6DQ3XG/ERo5wbcdOf5Q320dKtPCKPLR1LJs9VGXRaMa8l1uUa0tkCNOXiAxZUw==}
- engines: {node: '>=20.9.0'}
- cpu: [x64]
- os: [darwin]
-
- '@img/sharp-freebsd-wasm32@0.35.5':
- resolution: {integrity: sha512-Y/z91nEZ4uIBX5X3nfTovjU9lHNKFYbL2lpHCLVNmXQK03VIZvXBBt0KxbPGp2SdGSF+2mQU4e+hQaWOt86iAw==}
- engines: {node: '>=20.9.0'}
- os: [freebsd]
-
- '@img/sharp-libvips-darwin-arm64@1.3.4':
- resolution: {integrity: sha512-5R89nBYiRdUlSWJxPhO+GVtaXzXSxKnRu/xqMn3KTA3L9EB9Oy/P+Nn2f2vlhPuUdy/Zusb2DarbyTpGCfEDuw==}
- cpu: [arm64]
- os: [darwin]
-
- '@img/sharp-libvips-darwin-x64@1.3.4':
- resolution: {integrity: sha512-iR2OKH80yi0U+dUplyh3/xdpFvps6YkCwsXenIJxqxR1v9o+xtKTGbS9H7cps+2Vxjc8B1j96p75NmTGjIhtpQ==}
- cpu: [x64]
- os: [darwin]
-
- '@img/sharp-libvips-linux-arm64@1.3.4':
- resolution: {integrity: sha512-Y3dgX/6lE2QhQb+Gxy0WZxfg9MEm/JBjamZpS2IklP7xIQoKN4hzAm7KcMVGtaVDt3neE9OKBC7vAfonA/Lr1A==}
- cpu: [arm64]
- os: [linux]
- libc: [glibc]
-
- '@img/sharp-libvips-linux-arm@1.3.4':
- resolution: {integrity: sha512-LmRtTsOHuvM2+wlO2Db37dx5MiZhB0FvSunciw48YjdOkZz9KAiRbm8ujeMOA1INqmei5NapFxYEK1D1ZSidmw==}
- cpu: [arm]
- os: [linux]
- libc: [glibc]
-
- '@img/sharp-libvips-linux-ppc64@1.3.4':
- resolution: {integrity: sha512-Le6boB8Tai0Nis+gIxIpKx68UDVVIqdR8Tin5Yf1z2LJJQLDJvCDRqRu+jC2qCoD+eIomonmOwB4smBRxfVpYQ==}
- cpu: [ppc64]
- os: [linux]
- libc: [glibc]
-
- '@img/sharp-libvips-linux-riscv64@1.3.4':
- resolution: {integrity: sha512-aHkkIEHPRdQEegJN20MLmGtxYD9R2wQr3Cwpddnu5+YKMt6Uzax7S9h5gpZTo8wyrGuZSlfQ63OevL5mTyOC7Q==}
- cpu: [riscv64]
- os: [linux]
- libc: [glibc]
-
- '@img/sharp-libvips-linux-s390x@1.3.4':
- resolution: {integrity: sha512-ra/mB6MikESDUO7Yg+Mi95bFBb9GsObURuhnOv3OqknjGe9sZrG8tCe9q0xSIGrtLgvgw0gKnFWcK4blSgQOuQ==}
- cpu: [s390x]
- os: [linux]
- libc: [glibc]
-
- '@img/sharp-libvips-linux-x64@1.3.4':
- resolution: {integrity: sha512-GJ//SSXbnwSDes02umB3nDJLFcQzw8a18V8fyhqr6tV515tOEMdImjjxj1AoafMRz56F3PHgftnj1QEKSU1zkw==}
- cpu: [x64]
- os: [linux]
- libc: [glibc]
-
- '@img/sharp-libvips-linuxmusl-arm64@1.3.4':
- resolution: {integrity: sha512-hvulFwtjUcagsis6BBxHwGFwWoNZjgYmULGVrZcyfNbjA8hKILbRxGg15/7w5HDyXHXUos/j6baAWqnCyQ2DWA==}
- cpu: [arm64]
- os: [linux]
- libc: [musl]
-
- '@img/sharp-libvips-linuxmusl-x64@1.3.4':
- resolution: {integrity: sha512-6zXKeE/p39I1AmA3cJG35eyBGNqNddLnUXjhwBnsGjFPWqf5VKkDBEqaEkPDoTEtkxwi2vv8Tcr2mDyP4So7Fg==}
- cpu: [x64]
- os: [linux]
- libc: [musl]
-
- '@img/sharp-linux-arm64@0.35.5':
- resolution: {integrity: sha512-LYVx5JTsOM2CBzmxreh+nl64/3H6Xb09iSLknqH47z2T2DFFxDeFLP5y4dJwe6H7uGQlHPyEEtIqyo3DYsRwdQ==}
- engines: {node: '>=20.9.0'}
- cpu: [arm64]
- os: [linux]
- libc: [glibc]
-
- '@img/sharp-linux-arm@0.35.5':
- resolution: {integrity: sha512-LEaXK2WdXVK5ykcw0buWyPMsmLLL2vpHLD6yrNSW+JGEL3BZPA4tpKN6iaMc4AxTTAoaX/sU1rOL51lcIz48ZQ==}
- engines: {node: '>=20.9.0'}
- cpu: [arm]
- os: [linux]
- libc: [glibc]
-
- '@img/sharp-linux-ppc64@0.35.5':
- resolution: {integrity: sha512-QVxAAq8evVRI9ia2vqgwrmWucn5Dfv+JdWzj75pD8omHLPSP7f8p20O8jxzjCcuCEQEOtYOZUmX1hkiZ0kdevA==}
- engines: {node: '>=20.9.0'}
- cpu: [ppc64]
- os: [linux]
- libc: [glibc]
-
- '@img/sharp-linux-riscv64@0.35.5':
- resolution: {integrity: sha512-LtdreXguaavKODPIfzJ4kffx7UNt1omwtK0rch4EBbbSTXPnxWmYSayXdLJw0fJzQ97kHt1gL/yh4tvU+nCyRQ==}
- engines: {node: '>=20.9.0'}
- cpu: [riscv64]
- os: [linux]
- libc: [glibc]
-
- '@img/sharp-linux-s390x@0.35.5':
- resolution: {integrity: sha512-UZasTOFiYzotTsGOCu42BfUzP6Tu6Do/947iRm1RsLKvlllxwGcn4RN27LibGWceix4Y+Pmw3jsnTcCQIgWjqA==}
- engines: {node: '>=20.9.0'}
- cpu: [s390x]
- os: [linux]
- libc: [glibc]
-
- '@img/sharp-linux-x64@0.35.5':
- resolution: {integrity: sha512-SxFtLTeJInhAA9Q836kux2vZNeOBQEx658qvbboZScr0wIARym3IcGmW7KpVD5sbVg0Ojy+udFQdayYIZyoNog==}
- engines: {node: '>=20.9.0'}
- cpu: [x64]
- os: [linux]
- libc: [glibc]
-
- '@img/sharp-linuxmusl-arm64@0.35.5':
- resolution: {integrity: sha512-9HbMclmI1zlNkFRs3z9/eBtDjfD0sGlrX1z6b1qwmiFY5ElDLh4BC0LPBdVp7z1DXFiKlIcznf+ZlsuZzLxQqg==}
- engines: {node: '>=20.9.0'}
- cpu: [arm64]
- os: [linux]
- libc: [musl]
-
- '@img/sharp-linuxmusl-x64@0.35.5':
- resolution: {integrity: sha512-4KOphqB035HrVdqLZfCgMzzERrQkkzOwRhl4OAkRO1YCldbaFjySXMaK534Mo0V+LndnlJk+sbUyLeU0ULyD1A==}
- engines: {node: '>=20.9.0'}
- cpu: [x64]
- os: [linux]
- libc: [musl]
-
- '@img/sharp-wasm32@0.35.5':
- resolution: {integrity: sha512-Ptsga1su4tQx+LLF1ECS9U6nz5kmrXKo6XVbtR48Ke3ZRxxgaWBu7IDtEe1quo8hiupwm6WFqxVlXaSf7IINGQ==}
- engines: {node: '>=20.9.0'}
-
- '@img/sharp-webcontainers-wasm32@0.35.5':
- resolution: {integrity: sha512-hfhF/FmoQyTUkA0bIKFOtw536BQSeBMe6BF6QyWlrPxT754+TFLaZ7sKKTfvvM0yJgKgaYTwnFCIZ/GuDw5SUA==}
- engines: {node: '>=20.9.0'}
- cpu: [wasm32]
-
- '@img/sharp-win32-arm64@0.35.5':
- resolution: {integrity: sha512-X4t7g+7ZA5DKblCBEXGjUqqemj4vczING/5viFwAL8h4N3qYeyjwdCvRLHi4EdOUI+2Z7UFlp1VM+p/AuEtm6Q==}
- engines: {node: '>=20.9.0'}
- cpu: [arm64]
- os: [win32]
-
- '@img/sharp-win32-ia32@0.35.5':
- resolution: {integrity: sha512-5Zm82LoBc43nhwNybZlG7Y1KO//Zhsn306fQl29ZOuStHLGTo3BWL83q3cznX0poxSAMuYL1On/BHBxkBeKr6A==}
- engines: {node: ^20.9.0}
- cpu: [ia32]
- os: [win32]
-
- '@img/sharp-win32-x64@0.35.5':
- resolution: {integrity: sha512-x76eH0vEiHlcMQu8Y8IenntaACtddpT6W0wmXtWrnKcnKI7ME5DdgqhAD6SEWOEl1v2zDvkZDhFA9KnURwpfqg==}
- engines: {node: '>=20.9.0'}
- cpu: [x64]
- os: [win32]
-
- '@jridgewell/gen-mapping@0.3.13':
- resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
-
- '@jridgewell/remapping@2.3.5':
- resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
-
- '@jridgewell/resolve-uri@3.1.2':
- resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
- engines: {node: '>=6.0.0'}
-
- '@jridgewell/sourcemap-codec@1.6.0':
- resolution: {integrity: sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==}
-
- '@jridgewell/trace-mapping@0.3.31':
- resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
-
- '@next/env@16.4.2':
- resolution: {integrity: sha512-nTUTFH7G5/J/fmpkjVLegOkqyKOP0CEsJcMsyO4UCYeN1su+YMW/MfaSErnJskL7XM+UDK6aTvslxsRCyya/sA==}
-
- '@next/swc-darwin-arm64@16.4.2':
- resolution: {integrity: sha512-ONkhFvZNFWlsEHOM/81AtxdyuJP2KRYKYR0JxPwvcu1AuPMMMgcL+wW2luldJvMtZwKtUxoSkCychW5wIeoYSw==}
- engines: {node: '>= 10'}
- cpu: [arm64]
- os: [darwin]
-
- '@next/swc-darwin-x64@16.4.2':
- resolution: {integrity: sha512-luPCMbOsCoaF+kXJEUjmjmOZg1lC3BflhmUu+ZmW4tBu2vW/4AXak8JBFvePizGkxVmNiAw/r9ra+6UviCWtWQ==}
- engines: {node: '>= 10'}
- cpu: [x64]
- os: [darwin]
-
- '@next/swc-linux-arm64-gnu@16.4.2':
- resolution: {integrity: sha512-xhwFTAncJyaCNy5KqKKuKaIIdCy1/1ZV1s5S1G0hhT7wGMkDTlfJ6aQbfRFnIG/s3/kDrxQ8aycVe+c5QnP8ow==}
- engines: {node: '>= 10'}
- cpu: [arm64]
- os: [linux]
- libc: [glibc]
-
- '@next/swc-linux-arm64-musl@16.4.2':
- resolution: {integrity: sha512-T1PNmfbPcxr5ndtWUL/3wQtLXsz808lq6sc2GrNT5k2oquF7UyqZddHSuAewHVsWsGXe6nsl9HoN1YNriVjuSg==}
- engines: {node: '>= 10'}
- cpu: [arm64]
- os: [linux]
- libc: [musl]
-
- '@next/swc-linux-x64-gnu@16.4.2':
- resolution: {integrity: sha512-N9cDUOCGtkJG5PNKDFZUF3xXndrJJcpLp121uAGjIGvO/U2p9tfdNOM9htj7+5f72l0m8rMw/cvYacUJBQoudg==}
- engines: {node: '>= 10'}
- cpu: [x64]
- os: [linux]
- libc: [glibc]
-
- '@next/swc-linux-x64-musl@16.4.2':
- resolution: {integrity: sha512-yY2uh1YhX6ufuYy2FCbw1dqblbhI57GLYAJfCkqD9auTv6pLrH67Uccjc3QMKBeCYAG6lkgu08ExmX1bbjejjQ==}
- engines: {node: '>= 10'}
- cpu: [x64]
- os: [linux]
- libc: [musl]
-
- '@next/swc-win32-arm64-msvc@16.4.2':
- resolution: {integrity: sha512-j/ArWRIHpMMB6wYLMhr2puTguBt70lNU/Cmjl9p6dTDE8DGknYJMP9PdwPk2dqpCNL/KIX9yfngDvIesxJPmsg==}
- engines: {node: '>= 10'}
- cpu: [arm64]
- os: [win32]
-
- '@next/swc-win32-x64-msvc@16.4.2':
- resolution: {integrity: sha512-AA4edyWHDko3NCSo0x6GomsdgFb0oR1J3MXU1b5xt6FRFg4AucrMPW3S0hCe/9onU0O1BbpGQBsqo1r0Gneu1g==}
- engines: {node: '>= 10'}
- cpu: [x64]
- os: [win32]
-
- '@swc/helpers@0.5.23':
- resolution: {integrity: sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==}
-
- '@tailwindcss/node@4.3.3':
- resolution: {integrity: sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==}
-
- '@tailwindcss/oxide-android-arm64@4.3.3':
- resolution: {integrity: sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==}
- engines: {node: '>= 20'}
- cpu: [arm64]
- os: [android]
-
- '@tailwindcss/oxide-darwin-arm64@4.3.3':
- resolution: {integrity: sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==}
- engines: {node: '>= 20'}
- cpu: [arm64]
- os: [darwin]
-
- '@tailwindcss/oxide-darwin-x64@4.3.3':
- resolution: {integrity: sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==}
- engines: {node: '>= 20'}
- cpu: [x64]
- os: [darwin]
-
- '@tailwindcss/oxide-freebsd-x64@4.3.3':
- resolution: {integrity: sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==}
- engines: {node: '>= 20'}
- cpu: [x64]
- os: [freebsd]
-
- '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.3':
- resolution: {integrity: sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==}
- engines: {node: '>= 20'}
- cpu: [arm]
- os: [linux]
-
- '@tailwindcss/oxide-linux-arm64-gnu@4.3.3':
- resolution: {integrity: sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==}
- engines: {node: '>= 20'}
- cpu: [arm64]
- os: [linux]
- libc: [glibc]
-
- '@tailwindcss/oxide-linux-arm64-musl@4.3.3':
- resolution: {integrity: sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==}
- engines: {node: '>= 20'}
- cpu: [arm64]
- os: [linux]
- libc: [musl]
-
- '@tailwindcss/oxide-linux-x64-gnu@4.3.3':
- resolution: {integrity: sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==}
- engines: {node: '>= 20'}
- cpu: [x64]
- os: [linux]
- libc: [glibc]
-
- '@tailwindcss/oxide-linux-x64-musl@4.3.3':
- resolution: {integrity: sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==}
- engines: {node: '>= 20'}
- cpu: [x64]
- os: [linux]
- libc: [musl]
-
- '@tailwindcss/oxide-wasm32-wasi@4.3.3':
- resolution: {integrity: sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==}
- engines: {node: '>=14.0.0'}
- cpu: [wasm32]
- bundledDependencies:
- - '@napi-rs/wasm-runtime'
- - '@emnapi/core'
- - '@emnapi/runtime'
- - '@tybys/wasm-util'
- - '@emnapi/wasi-threads'
- - tslib
-
- '@tailwindcss/oxide-win32-arm64-msvc@4.3.3':
- resolution: {integrity: sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==}
- engines: {node: '>= 20'}
- cpu: [arm64]
- os: [win32]
-
- '@tailwindcss/oxide-win32-x64-msvc@4.3.3':
- resolution: {integrity: sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==}
- engines: {node: '>= 20'}
- cpu: [x64]
- os: [win32]
-
- '@tailwindcss/oxide@4.3.3':
- resolution: {integrity: sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==}
- engines: {node: '>= 20'}
-
- '@tailwindcss/postcss@4.3.3':
- resolution: {integrity: sha512-JTSZZGQi1AyKirbLN3azmjVzef92tcX7h+iSqPdaeStyFpGpDlKvvpxeOE8njhbUanbRwr3z8DyzhICWnMtQeg==}
-
- '@types/node@24.19.2':
- resolution: {integrity: sha512-93d49wCWJkCyN87MxLpNN6KXPCwFw7bVUg79mGUV1OS40JGWwVCr8n61DXCSqz7CV6/VfPkb7xec7uP2M+QHWQ==}
-
- '@types/react-dom@19.3.0':
- resolution: {integrity: sha512-ZI7bU42mZXXKHn/qNLEw2IrbiINU7X5+vfgdixBHkCNpYWXjKgfQ/P+uyGb5CjOLB9UcnTeg3rylQtV2hym44Q==}
- peerDependencies:
- '@types/react': ^19.3.0
-
- '@types/react@19.3.0':
- resolution: {integrity: sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg==}
-
- baseline-browser-mapping@2.11.32:
- resolution: {integrity: sha512-UvuxFU9P3hM29LrQdwu0cD6w6/+SFr+UlB9s/knI7+O2rK9xFxKUwSDWxGdbbqQ9/V7BJ5s0NI5nQAE4uJp3gQ==}
- engines: {node: '>=6.0.0'}
- hasBin: true
-
- caniuse-lite@1.0.30001819:
- resolution: {integrity: sha512-LFUqIIAwpzsIuevnKnsR9qnStBcgzPShTX61lBwN9uFkkf8o8zLiebEjbW8AYtZiF+1YKDWfdt/pWDtMuG8Xwg==}
-
- client-only@0.0.1:
- resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
-
- csstype@3.2.3:
- resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
-
- detect-libc@2.1.2:
- resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
- engines: {node: '>=8'}
-
- enhanced-resolve@5.26.0:
- resolution: {integrity: sha512-9vhedylFonb2YGogzUKX6+Ja72gOJbN1QHAqdrvqLwhdl/QWbKopzoUC9EbQNVsAns/bx/4uyqalrQAoy1IByw==}
- engines: {node: '>=10.13.0'}
-
- graceful-fs@4.2.11:
- resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
-
- jiti@2.7.0:
- resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==}
- hasBin: true
-
- lightningcss-android-arm64@1.32.0:
- resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==}
- engines: {node: '>= 12.0.0'}
- cpu: [arm64]
- os: [android]
-
- lightningcss-darwin-arm64@1.32.0:
- resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==}
- engines: {node: '>= 12.0.0'}
- cpu: [arm64]
- os: [darwin]
-
- lightningcss-darwin-x64@1.32.0:
- resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==}
- engines: {node: '>= 12.0.0'}
- cpu: [x64]
- os: [darwin]
-
- lightningcss-freebsd-x64@1.32.0:
- resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==}
- engines: {node: '>= 12.0.0'}
- cpu: [x64]
- os: [freebsd]
-
- lightningcss-linux-arm-gnueabihf@1.32.0:
- resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==}
- engines: {node: '>= 12.0.0'}
- cpu: [arm]
- os: [linux]
-
- lightningcss-linux-arm64-gnu@1.32.0:
- resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==}
- engines: {node: '>= 12.0.0'}
- cpu: [arm64]
- os: [linux]
- libc: [glibc]
-
- lightningcss-linux-arm64-musl@1.32.0:
- resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==}
- engines: {node: '>= 12.0.0'}
- cpu: [arm64]
- os: [linux]
- libc: [musl]
-
- lightningcss-linux-x64-gnu@1.32.0:
- resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==}
- engines: {node: '>= 12.0.0'}
- cpu: [x64]
- os: [linux]
- libc: [glibc]
-
- lightningcss-linux-x64-musl@1.32.0:
- resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==}
- engines: {node: '>= 12.0.0'}
- cpu: [x64]
- os: [linux]
- libc: [musl]
-
- lightningcss-win32-arm64-msvc@1.32.0:
- resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==}
- engines: {node: '>= 12.0.0'}
- cpu: [arm64]
- os: [win32]
-
- lightningcss-win32-x64-msvc@1.32.0:
- resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==}
- engines: {node: '>= 12.0.0'}
- cpu: [x64]
- os: [win32]
-
- lightningcss@1.32.0:
- resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==}
- engines: {node: '>= 12.0.0'}
-
- lucide-react@1.61.0:
- resolution: {integrity: sha512-v2SQPPPNjnr+BlhL9Spuzmo5yR+hLkftfuE4E3jaxdNPgSH0hJKPcLJBP7yAta87jQNPsSERS59PJjCJ/CorBA==}
- peerDependencies:
- '@types/react': '*'
- react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
- peerDependenciesMeta:
- '@types/react':
- optional: true
-
- magic-string@0.30.21:
- resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
-
- nanoid@3.3.20:
- resolution: {integrity: sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==}
- engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
- hasBin: true
-
- next@16.4.2:
- resolution: {integrity: sha512-r+oBJojfefUjOiWkBhXgLS+igxX/7BWyK59uHnyOyplMSLtBZ+QLP3okrdYTbrfrbrmNTVWLBPaHDX9KRaIt3w==}
- engines: {node: '>=20.9.0'}
- hasBin: true
- peerDependencies:
- '@opentelemetry/api': ^1.1.0
- '@playwright/test': ^1.51.1
- babel-plugin-react-compiler: '*'
- react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0
- react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0
- sass: ^1.3.0
- peerDependenciesMeta:
- '@opentelemetry/api':
- optional: true
- '@playwright/test':
- optional: true
- babel-plugin-react-compiler:
- optional: true
- sass:
- optional: true
-
- picocolors@1.1.1:
- resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
-
- postcss@8.5.23:
- resolution: {integrity: sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==}
- engines: {node: ^10 || ^12 || >=14}
-
- postcss@8.5.31:
- resolution: {integrity: sha512-YUbWYCgErwnMAVkjUnYa+KlMBzGpHwiIt/DE7f0G33AuX2LH9UcTk6KgWxd3zRU+pN3u/C+Xl3EnMLM4Hea7Sg==}
- engines: {node: ^10 || ^12 || >=14}
-
- react-dom@19.3.1:
- resolution: {integrity: sha512-Y0bARz53lhEC1NMCASs0/j+faB/zqt3R8hpvg1e8+61ZVJ4UL0UdC4cBbXfZMcIuhrfgeILTLe+ZeBCavQPtKQ==}
- peerDependencies:
- react: ^19.3.1
-
- react@19.3.1:
- resolution: {integrity: sha512-QNhWdt7nrgVWWQG58QuGsAR3jv3Hbe4mb4vz7w2csnHavciZJgda1CPNaldF6eVxv90ud3jUXpKlHL69gO38yw==}
- engines: {node: '>=0.10.0'}
-
- scheduler@0.28.0:
- resolution: {integrity: sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==}
-
- semver@7.8.5:
- resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==}
- engines: {node: '>=10'}
- hasBin: true
-
- sharp@0.35.5:
- resolution: {integrity: sha512-Ywn4OnzGukp7CDMrp08RQ50YKmuwG47brZgIVPTvBaaAfQlRlygrRqSrxdCiL9M+LlzLBiJ68IR1QqvzHyjC7g==}
- engines: {node: '>=20.9.0'}
- peerDependencies:
- '@types/node': '*'
- peerDependenciesMeta:
- '@types/node':
- optional: true
-
- source-map-js@1.2.2:
- resolution: {integrity: sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==}
- engines: {node: '>=0.10.0'}
-
- styled-jsx@5.1.6:
- resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==}
- engines: {node: '>= 12.0.0'}
- peerDependencies:
- '@babel/core': '*'
- babel-plugin-macros: '*'
- react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0'
- peerDependenciesMeta:
- '@babel/core':
- optional: true
- babel-plugin-macros:
- optional: true
-
- tailwindcss@4.3.3:
- resolution: {integrity: sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==}
-
- tapable@2.3.3:
- resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==}
- engines: {node: '>=6'}
-
- tslib@2.8.1:
- resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
-
- typescript@5.9.3:
- resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
- engines: {node: '>=14.17'}
- hasBin: true
-
- undici-types@7.24.6:
- resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==}
-
-snapshots:
-
- '@alloc/quick-lru@5.3.0': {}
-
- '@emnapi/runtime@1.11.3':
- dependencies:
- tslib: 2.8.1
- optional: true
-
- '@img/colour@1.1.0':
- optional: true
-
- '@img/sharp-darwin-arm64@0.35.5':
- optionalDependencies:
- '@img/sharp-libvips-darwin-arm64': 1.3.4
- optional: true
-
- '@img/sharp-darwin-x64@0.35.5':
- optionalDependencies:
- '@img/sharp-libvips-darwin-x64': 1.3.4
- optional: true
-
- '@img/sharp-freebsd-wasm32@0.35.5':
- dependencies:
- '@img/sharp-wasm32': 0.35.5
- optional: true
-
- '@img/sharp-libvips-darwin-arm64@1.3.4':
- optional: true
-
- '@img/sharp-libvips-darwin-x64@1.3.4':
- optional: true
-
- '@img/sharp-libvips-linux-arm64@1.3.4':
- optional: true
-
- '@img/sharp-libvips-linux-arm@1.3.4':
- optional: true
-
- '@img/sharp-libvips-linux-ppc64@1.3.4':
- optional: true
-
- '@img/sharp-libvips-linux-riscv64@1.3.4':
- optional: true
-
- '@img/sharp-libvips-linux-s390x@1.3.4':
- optional: true
-
- '@img/sharp-libvips-linux-x64@1.3.4':
- optional: true
-
- '@img/sharp-libvips-linuxmusl-arm64@1.3.4':
- optional: true
-
- '@img/sharp-libvips-linuxmusl-x64@1.3.4':
- optional: true
-
- '@img/sharp-linux-arm64@0.35.5':
- optionalDependencies:
- '@img/sharp-libvips-linux-arm64': 1.3.4
- optional: true
-
- '@img/sharp-linux-arm@0.35.5':
- optionalDependencies:
- '@img/sharp-libvips-linux-arm': 1.3.4
- optional: true
-
- '@img/sharp-linux-ppc64@0.35.5':
- optionalDependencies:
- '@img/sharp-libvips-linux-ppc64': 1.3.4
- optional: true
-
- '@img/sharp-linux-riscv64@0.35.5':
- optionalDependencies:
- '@img/sharp-libvips-linux-riscv64': 1.3.4
- optional: true
-
- '@img/sharp-linux-s390x@0.35.5':
- optionalDependencies:
- '@img/sharp-libvips-linux-s390x': 1.3.4
- optional: true
-
- '@img/sharp-linux-x64@0.35.5':
- optionalDependencies:
- '@img/sharp-libvips-linux-x64': 1.3.4
- optional: true
-
- '@img/sharp-linuxmusl-arm64@0.35.5':
- optionalDependencies:
- '@img/sharp-libvips-linuxmusl-arm64': 1.3.4
- optional: true
-
- '@img/sharp-linuxmusl-x64@0.35.5':
- optionalDependencies:
- '@img/sharp-libvips-linuxmusl-x64': 1.3.4
- optional: true
-
- '@img/sharp-wasm32@0.35.5':
- dependencies:
- '@emnapi/runtime': 1.11.3
- optional: true
-
- '@img/sharp-webcontainers-wasm32@0.35.5':
- dependencies:
- '@img/sharp-wasm32': 0.35.5
- optional: true
-
- '@img/sharp-win32-arm64@0.35.5':
- optional: true
-
- '@img/sharp-win32-ia32@0.35.5':
- optional: true
-
- '@img/sharp-win32-x64@0.35.5':
- optional: true
-
- '@jridgewell/gen-mapping@0.3.13':
- dependencies:
- '@jridgewell/sourcemap-codec': 1.6.0
- '@jridgewell/trace-mapping': 0.3.31
-
- '@jridgewell/remapping@2.3.5':
- dependencies:
- '@jridgewell/gen-mapping': 0.3.13
- '@jridgewell/trace-mapping': 0.3.31
-
- '@jridgewell/resolve-uri@3.1.2': {}
-
- '@jridgewell/sourcemap-codec@1.6.0': {}
-
- '@jridgewell/trace-mapping@0.3.31':
- dependencies:
- '@jridgewell/resolve-uri': 3.1.2
- '@jridgewell/sourcemap-codec': 1.6.0
-
- '@next/env@16.4.2': {}
-
- '@next/swc-darwin-arm64@16.4.2':
- optional: true
-
- '@next/swc-darwin-x64@16.4.2':
- optional: true
-
- '@next/swc-linux-arm64-gnu@16.4.2':
- optional: true
-
- '@next/swc-linux-arm64-musl@16.4.2':
- optional: true
-
- '@next/swc-linux-x64-gnu@16.4.2':
- optional: true
-
- '@next/swc-linux-x64-musl@16.4.2':
- optional: true
-
- '@next/swc-win32-arm64-msvc@16.4.2':
- optional: true
-
- '@next/swc-win32-x64-msvc@16.4.2':
- optional: true
-
- '@swc/helpers@0.5.23':
- dependencies:
- tslib: 2.8.1
-
- '@tailwindcss/node@4.3.3':
- dependencies:
- '@jridgewell/remapping': 2.3.5
- enhanced-resolve: 5.26.0
- jiti: 2.7.0
- lightningcss: 1.32.0
- magic-string: 0.30.21
- source-map-js: 1.2.2
- tailwindcss: 4.3.3
-
- '@tailwindcss/oxide-android-arm64@4.3.3':
- optional: true
-
- '@tailwindcss/oxide-darwin-arm64@4.3.3':
- optional: true
-
- '@tailwindcss/oxide-darwin-x64@4.3.3':
- optional: true
-
- '@tailwindcss/oxide-freebsd-x64@4.3.3':
- optional: true
-
- '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.3':
- optional: true
-
- '@tailwindcss/oxide-linux-arm64-gnu@4.3.3':
- optional: true
-
- '@tailwindcss/oxide-linux-arm64-musl@4.3.3':
- optional: true
-
- '@tailwindcss/oxide-linux-x64-gnu@4.3.3':
- optional: true
-
- '@tailwindcss/oxide-linux-x64-musl@4.3.3':
- optional: true
-
- '@tailwindcss/oxide-wasm32-wasi@4.3.3':
- optional: true
-
- '@tailwindcss/oxide-win32-arm64-msvc@4.3.3':
- optional: true
-
- '@tailwindcss/oxide-win32-x64-msvc@4.3.3':
- optional: true
-
- '@tailwindcss/oxide@4.3.3':
- optionalDependencies:
- '@tailwindcss/oxide-android-arm64': 4.3.3
- '@tailwindcss/oxide-darwin-arm64': 4.3.3
- '@tailwindcss/oxide-darwin-x64': 4.3.3
- '@tailwindcss/oxide-freebsd-x64': 4.3.3
- '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.3
- '@tailwindcss/oxide-linux-arm64-gnu': 4.3.3
- '@tailwindcss/oxide-linux-arm64-musl': 4.3.3
- '@tailwindcss/oxide-linux-x64-gnu': 4.3.3
- '@tailwindcss/oxide-linux-x64-musl': 4.3.3
- '@tailwindcss/oxide-wasm32-wasi': 4.3.3
- '@tailwindcss/oxide-win32-arm64-msvc': 4.3.3
- '@tailwindcss/oxide-win32-x64-msvc': 4.3.3
-
- '@tailwindcss/postcss@4.3.3':
- dependencies:
- '@alloc/quick-lru': 5.3.0
- '@tailwindcss/node': 4.3.3
- '@tailwindcss/oxide': 4.3.3
- postcss: 8.5.31
- tailwindcss: 4.3.3
-
- '@types/node@24.19.2':
- dependencies:
- undici-types: 7.24.6
-
- '@types/react-dom@19.3.0(@types/react@19.3.0)':
- dependencies:
- '@types/react': 19.3.0
-
- '@types/react@19.3.0':
- dependencies:
- csstype: 3.2.3
-
- baseline-browser-mapping@2.11.32: {}
-
- caniuse-lite@1.0.30001819: {}
-
- client-only@0.0.1: {}
-
- csstype@3.2.3: {}
-
- detect-libc@2.1.2: {}
-
- enhanced-resolve@5.26.0:
- dependencies:
- graceful-fs: 4.2.11
- tapable: 2.3.3
-
- graceful-fs@4.2.11: {}
-
- jiti@2.7.0: {}
-
- lightningcss-android-arm64@1.32.0:
- optional: true
-
- lightningcss-darwin-arm64@1.32.0:
- optional: true
-
- lightningcss-darwin-x64@1.32.0:
- optional: true
-
- lightningcss-freebsd-x64@1.32.0:
- optional: true
-
- lightningcss-linux-arm-gnueabihf@1.32.0:
- optional: true
-
- lightningcss-linux-arm64-gnu@1.32.0:
- optional: true
-
- lightningcss-linux-arm64-musl@1.32.0:
- optional: true
-
- lightningcss-linux-x64-gnu@1.32.0:
- optional: true
-
- lightningcss-linux-x64-musl@1.32.0:
- optional: true
-
- lightningcss-win32-arm64-msvc@1.32.0:
- optional: true
-
- lightningcss-win32-x64-msvc@1.32.0:
- optional: true
-
- lightningcss@1.32.0:
- dependencies:
- detect-libc: 2.1.2
- optionalDependencies:
- lightningcss-android-arm64: 1.32.0
- lightningcss-darwin-arm64: 1.32.0
- lightningcss-darwin-x64: 1.32.0
- lightningcss-freebsd-x64: 1.32.0
- lightningcss-linux-arm-gnueabihf: 1.32.0
- lightningcss-linux-arm64-gnu: 1.32.0
- lightningcss-linux-arm64-musl: 1.32.0
- lightningcss-linux-x64-gnu: 1.32.0
- lightningcss-linux-x64-musl: 1.32.0
- lightningcss-win32-arm64-msvc: 1.32.0
- lightningcss-win32-x64-msvc: 1.32.0
-
- lucide-react@1.61.0(@types/react@19.3.0)(react@19.3.1):
- dependencies:
- react: 19.3.1
- optionalDependencies:
- '@types/react': 19.3.0
-
- magic-string@0.30.21:
- dependencies:
- '@jridgewell/sourcemap-codec': 1.6.0
-
- nanoid@3.3.20: {}
-
- next@16.4.2(@types/node@24.19.2)(react-dom@19.3.1(react@19.3.1))(react@19.3.1):
- dependencies:
- '@next/env': 16.4.2
- '@swc/helpers': 0.5.23
- baseline-browser-mapping: 2.11.32
- caniuse-lite: 1.0.30001819
- postcss: 8.5.23
- react: 19.3.1
- react-dom: 19.3.1(react@19.3.1)
- styled-jsx: 5.1.6(react@19.3.1)
- optionalDependencies:
- '@next/swc-darwin-arm64': 16.4.2
- '@next/swc-darwin-x64': 16.4.2
- '@next/swc-linux-arm64-gnu': 16.4.2
- '@next/swc-linux-arm64-musl': 16.4.2
- '@next/swc-linux-x64-gnu': 16.4.2
- '@next/swc-linux-x64-musl': 16.4.2
- '@next/swc-win32-arm64-msvc': 16.4.2
- '@next/swc-win32-x64-msvc': 16.4.2
- sharp: 0.35.5(@types/node@24.19.2)
- transitivePeerDependencies:
- - '@babel/core'
- - '@types/node'
- - babel-plugin-macros
-
- picocolors@1.1.1: {}
-
- postcss@8.5.23:
- dependencies:
- nanoid: 3.3.20
- picocolors: 1.1.1
- source-map-js: 1.2.2
-
- postcss@8.5.31:
- dependencies:
- nanoid: 3.3.20
- picocolors: 1.1.1
- source-map-js: 1.2.2
-
- react-dom@19.3.1(react@19.3.1):
- dependencies:
- react: 19.3.1
- scheduler: 0.28.0
-
- react@19.3.1: {}
-
- scheduler@0.28.0: {}
-
- semver@7.8.5:
- optional: true
-
- sharp@0.35.5(@types/node@24.19.2):
- dependencies:
- '@img/colour': 1.1.0
- detect-libc: 2.1.2
- semver: 7.8.5
- optionalDependencies:
- '@img/sharp-darwin-arm64': 0.35.5
- '@img/sharp-darwin-x64': 0.35.5
- '@img/sharp-freebsd-wasm32': 0.35.5
- '@img/sharp-libvips-darwin-arm64': 1.3.4
- '@img/sharp-libvips-darwin-x64': 1.3.4
- '@img/sharp-libvips-linux-arm': 1.3.4
- '@img/sharp-libvips-linux-arm64': 1.3.4
- '@img/sharp-libvips-linux-ppc64': 1.3.4
- '@img/sharp-libvips-linux-riscv64': 1.3.4
- '@img/sharp-libvips-linux-s390x': 1.3.4
- '@img/sharp-libvips-linux-x64': 1.3.4
- '@img/sharp-libvips-linuxmusl-arm64': 1.3.4
- '@img/sharp-libvips-linuxmusl-x64': 1.3.4
- '@img/sharp-linux-arm': 0.35.5
- '@img/sharp-linux-arm64': 0.35.5
- '@img/sharp-linux-ppc64': 0.35.5
- '@img/sharp-linux-riscv64': 0.35.5
- '@img/sharp-linux-s390x': 0.35.5
- '@img/sharp-linux-x64': 0.35.5
- '@img/sharp-linuxmusl-arm64': 0.35.5
- '@img/sharp-linuxmusl-x64': 0.35.5
- '@img/sharp-webcontainers-wasm32': 0.35.5
- '@img/sharp-win32-arm64': 0.35.5
- '@img/sharp-win32-ia32': 0.35.5
- '@img/sharp-win32-x64': 0.35.5
- '@types/node': 24.19.2
- optional: true
-
- source-map-js@1.2.2: {}
-
- styled-jsx@5.1.6(react@19.3.1):
- dependencies:
- client-only: 0.0.1
- react: 19.3.1
-
- tailwindcss@4.3.3: {}
-
- tapable@2.3.3: {}
-
- tslib@2.8.1: {}
-
- typescript@5.9.3: {}
-
- undici-types@7.24.6: {}
diff --git a/apps/studio/postcss.config.mjs b/apps/studio/postcss.config.mjs
deleted file mode 100644
index a2dc18a..0000000
--- a/apps/studio/postcss.config.mjs
+++ /dev/null
@@ -1,3 +0,0 @@
-export default {
- plugins: { "@tailwindcss/postcss": {} },
-};
diff --git a/apps/studio/scripts/graphic-smoke.cjs b/apps/studio/scripts/graphic-smoke.cjs
deleted file mode 100644
index c9a1efd..0000000
--- a/apps/studio/scripts/graphic-smoke.cjs
+++ /dev/null
@@ -1,24 +0,0 @@
-const {chromium}=require('playwright-core');
-const assert=require('node:assert/strict');
-(async()=>{const browser=await chromium.launch({channel:'chrome',headless:true});try{const page=await browser.newPage({viewport:{width:1440,height:1000}});const errors=[];page.on('pageerror',e=>errors.push(e.message));
- await page.route('**/api/account/session',r=>r.fulfill({json:{user:null}}));
- await page.goto((process.env.STUDIO_TEST_ORIGIN||'http://8.211.154.134:18131')+'/graphic');
- await page.getByRole('button',{name:'切换图层面板',exact:true}).click();
- assert.equal(await page.getByRole('button',{name:'图层',exact:true}).isVisible(),false);
- await page.getByRole('button',{name:'切换图层面板',exact:true}).click();
- await page.getByRole('button',{name:'切换属性面板',exact:true}).click();
- assert.equal(await page.getByRole('button',{name:'备份设计 JSON',exact:true}).isVisible(),false);
- await page.getByRole('button',{name:'切换属性面板',exact:true}).click();
- await page.getByRole('button',{name:'添加文字',exact:true}).click();
- await page.getByRole('textbox',{name:'文字内容',exact:true}).fill('设计从这里开始');
- await page.getByRole('button',{name:'添加矩形',exact:true}).click();
- await page.getByRole('button',{name:'撤销',exact:true}).click();
- await page.getByRole('button',{name:'重做',exact:true}).click();
- await page.reload();await page.getByRole('button',{name:'文字',exact:true}).first().waitFor();
- assert.ok(await page.evaluate(()=>localStorage.getItem('studio.graphic.v1').includes('设计从这里开始')));
- const file=page.waitForEvent('download');await page.getByRole('button',{name:'导出 SVG',exact:true}).click();assert.ok((await file).suggestedFilename().endsWith('.svg'));
- await page.getByRole('button',{name:'邮箱登录',exact:true}).click();await page.getByRole('dialog').waitFor();await page.keyboard.press('Escape');await page.getByRole('dialog').waitFor({state:'hidden'});
- await page.screenshot({path:process.env.STUDIO_QA_SCREENSHOT||'graphic-qa.png',fullPage:true});
- await page.setViewportSize({width:390,height:844});assert.equal(await page.evaluate(()=>document.documentElement.scrollWidth>innerWidth),false);
- assert.deepEqual(errors,[]);console.log('Graphic editing, history, restore, SVG download, account dialog and mobile overflow checks passed.');
- }finally{await browser.close()}})().catch(e=>{console.error(e);process.exitCode=1});
diff --git a/apps/studio/scripts/smoke.mjs b/apps/studio/scripts/smoke.mjs
deleted file mode 100644
index 729976b..0000000
--- a/apps/studio/scripts/smoke.mjs
+++ /dev/null
@@ -1,29 +0,0 @@
-/** CI-only isolated runtime checks, never a local preview workflow. */
-import {readFileSync} from 'node:fs';
-import {spawn} from 'node:child_process';import {once} from 'node:events';import {createServer} from 'node:net';import {createServer as createHttpServer} from 'node:http';import assert from 'node:assert/strict';import {setTimeout} from 'node:timers/promises';
-const designId='00000000-0000-4000-8000-000000000001',missingId='00000000-0000-4000-8000-000000000002';
-const standardId='00000000-0000-4000-8000-000000000003';
-const seriesId='00000000-0000-4000-8000-000000000004';
-const doc=JSON.parse(readFileSync(new URL('../fixtures/autumn-journal.json',import.meta.url))).document;
-const assetId='00000000-0000-4000-8000-000000000005';doc.sources=[{assetId,author:'CI fixture',license:'test only',url:'generated',prompt:'test image',tool:'fixture'}];for(const p of doc.pages)p.parameters.images.I01.assetId=assetId;
-let reads=0,mediaReads=0;
-const wiki=createHttpServer((req,res)=>{assert.equal(req.headers.cookie,'session=smoke-test');if(/^\/api\/media\/[0-9a-f-]{36}$/.test(req.url)){mediaReads++;res.setHeader('Content-Type','image/png');return res.end(Buffer.from('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+j3ioAAAAASUVORK5CYII=','base64'))}reads++;res.setHeader('Content-Type','application/json');if(req.url.endsWith(seriesId))return res.end(JSON.stringify({design:{id:seriesId,name:'完整三页作品',layoutId:'standard-01',revision:1,url:'/studio/template-layout?id='+seriesId,parameters:doc.pages[0].parameters,document:doc}}));const standard=req.url.endsWith(standardId);if(!standard&&!req.url.endsWith(designId)){res.writeHead(404);return res.end('{}')}res.end(JSON.stringify({design:{id:standard?standardId:designId,name:'已保存的实际页面',layoutId:standard?'standard-01':'ref-01',revision:3,url:'/studio/designs/'+designId,parameters:{added:[{id:'user-smoke',kind:'text',role:'Added text',box:[10,10,20,10],direction:'horizontal',text:'新增元素已恢复',reading:'custom'}],layers:{T01:{x:12,rotation:25,opacity:.7},'user-smoke':{z:12}},texts:{T01:{value:'确定的页面文字',color:'#123456'}},images:{I01:{color:'#abcdef'}},decorations:{D01:{hidden:true}},paper:'#eeeeee'}}}))});
-wiki.listen(0,'127.0.0.1');await once(wiki,'listening');
-const socket=createServer();socket.listen(0,'127.0.0.1');await once(socket,'listening');const port=socket.address().port;await new Promise(r=>socket.close(r));const child=spawn(process.execPath,[process.env.STUDIO_STANDALONE_SERVER || '.next/standalone/apps/studio/server.js'],{env:{...process.env,PORT:String(port),HOSTNAME:'127.0.0.1',STUDIO_WIKI_ORIGIN:'http://127.0.0.1:'+wiki.address().port},stdio:'inherit'}),base='http://127.0.0.1:'+port;
-try{let ready=false;for(let i=0;i<60;i++){try{if((await fetch(base+'/studio/api/health')).ok){ready=true;break}}catch{}await setTimeout(250)}assert.ok(ready);const entry=await fetch(base+'/studio',{redirect:'manual'});assert.equal(entry.status,307);assert.equal(entry.headers.get('location'),'/studio/graphic');const library=await fetch(base+'/studio/graphic').then(r=>r.text());assert.ok(library.includes('GRAPHIC'));assert.ok(!library.includes('ref-27')); const catalog=await fetch(base+'/studio/api/layouts').then(r=>r.json());assert.equal(catalog.layouts.length,28);
-for(const l of catalog.layouts){const page=await fetch(base+l.url);assert.equal(page.status,200,l.id);const html=await page.text();assert.ok(html.includes(l.name));assert.ok(html.includes('data-layout-id="'+l.id+'"'));assert.ok(!/