diff --git a/.gitignore b/.gitignore index 9cc8279..d76db99 100644 --- a/.gitignore +++ b/.gitignore @@ -13,13 +13,17 @@ coverage/ .env .env.* !.env.example -!miniProgram/.env.weapp.example project.private.config.json +**/project.private.config.json +!miniProgram/.env.example -# Local WeChat DevTools automation artifacts +# WeChat automation local state and evidence qa-screenshots/weapp-actual/ qa-screenshots/weapp-logs/ -miniProgram/automation-artifacts/ +qa-artifacts/ +**/qa-artifacts/ +weapp-automation.log +**/weapp-automation.log # Taro/SWC compiler cache (platform-specific binaries) miniProgram/.swc/ @@ -42,6 +46,3 @@ ehthumbs.db *.log *.tmp tmp/ - -# Superseded local dependency bootstrap (the formal client lives in miniProgram/) -taro/ diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..51ab392 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,10 @@ +# BITerStore Agent Rules + +- `web/` 是视觉与行为 Golden Reference;迁移期间不得删除、重命名或为实现便利而重设计。 +- 可见页面修改完成后必须运行 `miniProgram` 的 lint、test、H5 build 和 WeApp build;微信服务端口可用时还必须运行仓库内 E2E。 +- 微信验收必须检查当前 route、稳定 `e2e-*` 元素、console/exception、结构快照和截图。 +- 页面不得直接使用浏览器或微信专属 API;平台差异必须进入 `src/platform`。 +- 不得上传体验版、提审、发布、修改用户 AppID、生成上传私钥或更改开发者工具安全设置。 +- `.env.weapp.local`、`project.private.config.json`、CLI token、端口和实际失败工件不得提交。 +- 社区 MCP 不是验收依据,不得暴露 `run_js`;确定性基线始终是版本化 E2E 脚本。 +- 只允许本地里程碑提交;推送、部署和其他远端写入必须再次取得用户确认。 diff --git a/BITerStore_TARO_MIGRATION_AGENT.md b/BITerStore_TARO_MIGRATION_AGENT.md deleted file mode 100644 index 2bfd886..0000000 --- a/BITerStore_TARO_MIGRATION_AGENT.md +++ /dev/null @@ -1,1253 +0,0 @@ -# BITerStore — Taro 双端迁移 Agent 执行说明 - -> 目标:在**不丢失当前 H5 高保真原型成果**的前提下,将 BITerStore 正式前端迁移为 **Taro + React**,以 **微信小程序为主产物、H5 为第二产物**,实现“一套业务核心 + 少量平台适配”的双端架构。 -> -> 核心原则:**Behavior parity first, feature expansion second.** -> -> 本文档是本轮迁移任务的最高优先级执行说明。若它与仓库中旧版 `TODO.md` / Agent 指南存在冲突,以本文档为准;但不得擅自删除旧文档,应在迁移完成后同步更新。 - ---- - -## 0. 开始前必须做的事 - -Agent 在修改任何代码前,必须依次完成: - -1. 阅读仓库根目录: - - `README.md` - - `TODO.md` - - `Agent工作指南.md`(文件名可能经过编码) -2. 阅读当前前端关键文件: - - `web/app/components/mobile-app.tsx` - - `web/app/components/client-mobile-app.tsx` - - `web/app/lib/repository.ts` - - `web/app/lib/types.ts` - - `web/app/lib/demo-data.ts` - - `web/app/lib/image-store.ts` - - `web/app/globals.css` - - `web/package.json` -3. 浏览 `qa-screenshots/` 中现有 360 / 390 / 430px 验收截图。 -4. 检查 Git 状态和最近提交: - ```bash - git status - git log --oneline --decorate -n 15 - git tag --list - ``` -5. **不得在工作区有未提交改动时开始迁移。** -6. 更新根目录 `TODO.md`,新增“Taro 迁移”阶段,并持续维护完成状态。 - ---- - -# 1. 当前项目基线 - -当前仓库已经有一套完整的移动端 H5 高保真交互原型。 - -现状包括: - -- React 19 + TypeScript -- Next / Vinext / Vite 构建链 -- 自定义 CSS 视觉系统 -- `DemoRepository` 异步数据边界 -- LocalStorage -- IndexedDB 图片持久化 -- Service Worker 资源缓存 -- Vitest 单元测试 -- 360 / 390 / 430px 移动端视觉验收截图 - -当前已经实现的主要业务闭环: - -```text -欢迎 / 新手引导 - ↓ -首页 - ↓ -搜索 / 分类 / 筛选 - ↓ -商品详情 - ↓ -收藏 / 联系卖家 - ↓ -站内聊天 - ↓ -校内线下交易 - -以及: - -发布闲置 - ↓ -图片上传 - ↓ -Tobby 一键成文(当前为本地规则模拟) - ↓ -完善信息 - ↓ -预览 - ↓ -发布 -``` - -当前 H5 **不是废弃代码**。 - -它将作为: - -- 迁移行为基准 -- 视觉 Golden Reference -- 双端回归对照 -- 可复用业务逻辑来源 -- 素材与 Design Token 来源 - ---- - -# 2. Git 策略:同仓库迁移,不新开仓库 - -## 2.1 禁止创建独立 `BITerStore-Taro` 仓库 - -Taro 版本仍属于同一个 BITerStore 产品,因此: - -**必须继续使用当前 Git 仓库。** - -不要建立两个长期独立维护的前端仓库,否则会导致: - -- Design Token 分叉 -- Tobby 素材版本不一致 -- BookCard 等业务组件修复不同步 -- API 类型重复维护 -- 产品功能出现双版本漂移 - ---- - -## 2.2 给当前稳定 H5 打里程碑 Tag - -确认当前 `main` 干净且当前构建确实对应稳定 H5 基线后: - -```bash -git switch main -git status -``` - -若当前稳定版本还没有合适的里程碑 Tag,则创建: - -```bash -git tag h5-prototype-v0.1 -git push origin h5-prototype-v0.1 -``` - -如果仓库已经存在含义相同的稳定 Tag: - -**不要重复创建。** - -禁止: - -```bash -git tag -f ... -git push --force ... -``` - -除非项目负责人明确要求。 - ---- - -## 2.3 创建迁移分支 - -```bash -git switch -c refactor/taro-migration -``` - -后续所有迁移工作先在: - -```text -refactor/taro-migration -``` - -进行。 - -在双端验收完成前: - -**不要直接破坏 `main`。** - ---- - -# 3. 本轮迁移的真正目标 - -目标不是: - -> “把现有 React 网页勉强塞进小程序。” - -目标是: - -> **重新建立一套以 Taro React 为正式客户端基座的跨端前端,同时最大限度复用当前业务模型、素材、交互和视觉系统。** - -最终主要产物: - -```text -Taro React Source - │ - ├── 微信小程序(主产物) - │ - └── H5(第二产物) -``` - -预期代码共享模式: - -```text - Shared Business Core - 页面业务 / 类型 / API / 状态 - │ - Platform Adapters - ↙ ↘ - WeChat H5 -``` - -目标不是 100% 无条件共享。 - -合理目标: - -- 主体业务页面与组件:高度共享 -- 类型 / Repository / Domain:尽量 100% 共享 -- 登录 / 分享 / 存储 / 图片 / 通知:平台适配 -- 极少数 UI 或 API:按端差异实现 - ---- - -# 4. 目录策略:迁移期间保留现有 `web/` - -为了避免一次性重命名导致大量无意义 Git diff,本阶段**不要立刻移动或删除现有 `web/`**。 - -建议迁移阶段使用: - -```text -BITerStore/ -├─ Assets/ -├─ qa-screenshots/ -│ -├─ web/ # 当前 H5 基线,迁移期间保持可运行 -│ -├─ taro/ # 新正式客户端 -│ ├─ src/ -│ │ ├─ pages/ -│ │ ├─ components/ -│ │ ├─ domain/ -│ │ ├─ repository/ -│ │ ├─ services/ -│ │ ├─ platform/ -│ │ ├─ styles/ -│ │ └─ assets/ -│ ├─ config/ -│ └─ package.json -│ -├─ packages/ # 仅在真正有复用价值时建立 -│ ├─ domain/ -│ ├─ design-tokens/ -│ └─ shared/ -│ -├─ README.md -├─ TODO.md -└─ TARO_MIGRATION_AGENT.md -``` - -注意: - -**不要为了“架构看起来漂亮”立刻把所有东西抽成 package。** - -优先做到: - -1. 能运行 -2. 能双端构建 -3. 行为一致 -4. 视觉一致 -5. 再做抽象 - -避免过早工程化。 - ---- - -# 5. Taro 技术基座 - -使用: - -- Taro -- React -- TypeScript - -版本原则: - -- 使用迁移时的稳定、兼容版本 -- 不要为了追最新版同时升级大量无关依赖 -- 避免一次迁移同时进行 React 大版本实验 - -核心代码必须使用跨端组件,例如: - -```tsx -import { - View, - Text, - Image, - Input, - ScrollView, -} from '@tarojs/components' -``` - -禁止在需要编译到微信小程序的共享页面中大量继续使用: - -```tsx -
- - - -``` - -也不要继续依赖: - -- `window` -- `document` -- `history.pushState` -- `localStorage` -- `indexedDB` -- DOM query -- Web-only lifecycle - -这些能力必须隔离到平台层。 - ---- - -# 6. 迁移优先级:先复刻,不新增 - -第一阶段必须坚持: - -> **Behavior parity first.** - -即先让 Taro 版本完整复刻当前稳定 H5 已经存在的行为。 - -本轮迁移阶段暂时不要顺手大规模加入: - -- 新版 EXP 个人中心 -- 粉丝 / 关注社交系统 -- “关于 Tobby” -- Tobby MBTI 投票 -- 真正的大模型接口 -- 真正校园认证 -- 真支付 -- 新后端 API -- 全新功能重设计 - -这些已经有产品设计方向,但属于: - -```text -Phase 2 — Feature Expansion -``` - -而不是基础迁移阶段。 - ---- - -# 7. 产品命名更新:第二导航项统一为“搜索” - -当前旧版 H5 / `TODO.md` 中底栏第二项曾写作: - -```text -分类 -``` - -最新产品决策已经更新为: - -```text -首页 / 搜索 / 发布 / 消息 / 我的 -``` - -因此 Taro 正式版本: - -**第二导航项统一显示为“搜索”。** - -旧 `/category` 页中的能力并不丢弃,而是整合为: - -```text -Search Page -├─ 搜索框 -├─ 类别快捷筛选 -├─ 校区 -├─ 成色 -├─ 价格 -├─ 排序 -├─ 只看可交易 -├─ 高级筛选 -└─ 搜索结果 -``` - -可以在迁移期内部继续复用 category 相关数据结构,但用户可见命名应迁移到“搜索”。 - ---- - -# 8. 页面拆分要求 - -当前 H5 中 `mobile-app.tsx` 承载了较多页面和路由逻辑。 - -Taro 重构时禁止继续把全部页面塞进一个超级组件。 - -建议至少拆分: - -```text -src/pages/ -├─ welcome/ -├─ onboarding/ -├─ home/ -├─ search/ -├─ book-detail/ -├─ publish/ -├─ messages/ -├─ notification-detail/ -├─ chat/ -├─ profile/ -├─ favorites/ -├─ my-listings/ -└─ states/ -``` - -通用组件拆分: - -```text -src/components/ -├─ AppShell/ -├─ BottomNav/ -├─ BrandHeader/ -├─ BookCard/ -├─ BookList/ -├─ SearchBar/ -├─ FilterChip/ -├─ Tobby/ -├─ TobbyBubble/ -├─ EmptyState/ -├─ Toast/ -├─ Modal/ -├─ FormField/ -└─ StatusTag/ -``` - -原则: - -**按稳定复用价值拆,不按“看起来组件化”机械拆。** - ---- - -# 9. Repository 层必须保留 - -当前工程一个重要优点是: - -> UI 不直接依赖 LocalStorage / IndexedDB,而通过 `DemoRepository` 访问数据。 - -这个设计必须保留。 - -目标结构: - -```text -UI - │ -Repository Interface - │ -├── DemoRepository -└── ApiRepository(未来) -``` - -页面禁止出现: - -```ts -localStorage.getItem(...) -indexedDB.open(...) -fetch('/api/...') // 若未来接口层已有 Repository 时 -``` - -业务 UI 应只调用统一接口。 - -例如: - -```ts -repository.listBooks() -repository.getBook(id) -repository.toggleFavorite(id) -repository.saveDraft(draft) -repository.publishListing(listing) -repository.listMessages() -repository.sendMessage(...) -``` - -这样未来接真实后端时,只需要替换 Repository 实现。 - ---- - -# 10. Platform Adapter - -必须建立明确的平台适配边界。 - -建议: - -```text -src/platform/ -├─ auth/ -├─ navigation/ -├─ storage/ -├─ media/ -├─ share/ -├─ notification/ -└─ cache/ -``` - -允许采用 Taro 环境判断或平台文件: - -```text -auth.weapp.ts -auth.h5.ts - -share.weapp.ts -share.h5.ts - -storage.weapp.ts -storage.h5.ts -``` - -上层业务代码只调用统一接口。 - ---- - -## 10.1 Navigation - -当前 H5 中存在: - -```text -window.history.pushState -history.back -window.location.pathname -popstate -``` - -Taro 端迁移为统一导航封装: - -```ts -navigateTo(...) -navigateBack(...) -switchTab(...) -replace(...) -``` - -底层可使用: - -```ts -Taro.navigateTo -Taro.navigateBack -Taro.switchTab -Taro.redirectTo -``` - -业务页面不要直接依赖浏览器 history。 - ---- - -## 10.2 Storage - -当前: - -```text -LocalStorage -IndexedDB -``` - -迁移目标: - -```text -StorageAdapter -├─ H5 implementation -└─ WeApp implementation -``` - -普通状态可使用: - -```ts -Taro.setStorage -Taro.getStorage -``` - -大图片或临时文件不要粗暴塞入普通 storage。 - ---- - -## 10.3 图片选择 / 上传 - -当前 Web 端的: - -```html - -``` - -微信端不能直接复用。 - -建立: - -```text -MediaAdapter -``` - -例如: - -```ts -chooseImages() -compressImage() -readImageMetadata() -``` - -微信实现可以基于 Taro / 小程序媒体 API。 - -H5 实现则继续使用浏览器文件选择能力。 - ---- - -## 10.4 分享 - -业务层只传: - -```ts -{ - type: 'book', - id: book.id, - title: book.title -} -``` - -平台层负责转换: - -H5: - -```text -https://.../books/:id -``` - -微信: - -```text -/pages/book-detail/index?id=:id -``` - -不要在业务层假设小程序分享是 HTML `` 标签。 - ---- - -## 10.5 通知 - -微信订阅消息 / H5 Web Notification 等能力必须独立适配。 - -迁移阶段如果当前 Demo 没有真实通知能力: - -**保持模拟,不要顺便接真实服务。** - ---- - -## 10.6 Service Worker / Cache - -当前 H5 的 Service Worker: - -- 可以继续留在 legacy H5 -- Taro H5 可单独评估是否继续使用 -- 微信小程序端不要照搬 - -微信端缓存逻辑应遵循小程序自己的资源与文件机制。 - ---- - -# 11. Design System 必须复用 - -现有视觉 Token: - -```text -Primary Sage #6F7956 -Dark Olive #4F5940 -Cream Background #F7F4EA -Warm Border #D5C7A7 -Price Accent #C56E3B -Holographic Aqua #78D8C6 -``` - -迁移时应建立统一 Token,例如: - -```ts -export const colors = { - primarySage: '#6F7956', - darkOlive: '#4F5940', - creamBackground: '#F7F4EA', - warmBorder: '#D5C7A7', - priceAccent: '#C56E3B', - holographicAqua: '#78D8C6', -} -``` - -禁止迁移过程中因为方便: - -- 换成默认蓝色 -- 换 UI 框架默认主题 -- 用微信原生灰色组件替代全部视觉 -- 把 BITerStore 改成普通商城风格 - ---- - -# 12. 不要擅自重新设计 UI - -`qa-screenshots/` 是当前稳定 H5 的 **Golden Visual Reference**。 - -迁移时必须遵循: - -> 当实现方便性与当前视觉发生冲突时,优先尝试保持当前视觉;确实存在平台限制时,再做最小差异适配并记录。 - -禁止 Agent: - -- 自己重新布局首页 -- 擅自改字号体系 -- 更换主色 -- 删除 Tobby -- 改造成标准 Taro Demo 风格 -- 用整页截图代替真实 UI - -所有页面必须仍由真实组件实现。 - ---- - -# 13. Bottom Navigation - -正式产品导航: - -```text -首页 -搜索 -发布 -消息 -我的 -``` - -视觉上保持现有高保真底栏语言: - -- 大圆角 -- 鼠尾草绿激活态 -- 中间发布入口重点突出 -- Tobby / 小型叶片点缀适度使用 - -不要仅为了省开发时间直接切换成完全不同风格的系统默认 TabBar。 - -如果微信小程序导航机制要求使用原生 / custom tabBar: - -- 将差异隔离 -- 保持用户可见视觉尽量一致 -- 不影响页面业务组件 - ---- - -# 14. Tobby 资产迁移规则 - -Tobby 是产品 Identity,不是普通插图。 - -必须保留: - -- 现有 Character Master -- 简化小尺寸素材 -- 状态插画 -- 表情素材 -- 背景图 -- 欢迎页素材 - -迁移时: - -- 不覆盖原始 `Assets/` -- 使用 WebP / 合理压缩版本作为运行资源 -- 不把超大 PNG 原图直接塞进首屏 -- 首屏关键 Tobby 素材可预加载 -- 非首屏素材按需加载 -- 长列表避免重复加载大图 - ---- - -# 15. 发布页:Tobby 一键成文 - -当前功能是: - -```text -本地规则模拟 -``` - -本阶段迁移必须保持这个行为,而不是直接接真实 AI。 - -建议抽象接口: - -```ts -interface ListingAssistant { - generate(input: ListingAIInput): Promise -} -``` - -当前: - -```text -DemoListingAssistant -``` - -未来: - -```text -MultimodalListingAssistant -``` - -预期未来结构化返回: - -```ts -{ - title, - author, - isbn, - category, - course, - suggestedCondition, - suggestedPrice, - description, - tags -} -``` - -页面只消费结构化结果,不依赖具体模型。 - ---- - -# 16. 聊天页 - -迁移必须保持现有演示能力: - -- 文本消息 -- 图片消息 -- 站内书籍链接 -- 未读状态 -- 交易安全提醒 - -平台 UI 与 Repository 分离。 - -暂时不要引入复杂 IM SDK,除非项目负责人另行决定。 - ---- - -# 17. 性能重点 - -BITerStore 当前性能风险主要不是复杂计算,而是: - -- Tobby 大图 -- 背景 BG -- 商品封面 -- 长列表 -- 多张发布图片 - -优先: - -- 图片压缩 -- 合理尺寸 -- lazy load -- 分页 / 增量加载 -- 首屏资源控制 -- 避免大面积无意义动画 - -不要为了“GPU 加速”进行过度优化。 - -禁止迁移阶段引入: - -- 重 WebGL 特效 -- 大型粒子系统 -- 高成本骨骼动画 - -除非明确需求。 - ---- - -# 18. 推荐迁移顺序 - -必须分阶段迁移,不要一次性全部推倒。 - -## Phase 0 — Baseline Freeze - -- [ ] 确认 `main` 干净 -- [ ] 确认当前 H5 可运行 -- [ ] 确认 / 创建稳定 Tag -- [ ] 建立 `refactor/taro-migration` -- [ ] 更新 TODO - ---- - -## Phase 1 — Taro Skeleton - -- [ ] 初始化 `taro/` -- [ ] Taro React + TypeScript -- [ ] 微信小程序构建成功 -- [ ] H5 构建成功 -- [ ] 建立基础 App Shell -- [ ] 建立页面路由 -- [ ] 建立 Design Tokens -- [ ] 建立 Platform Adapter 空接口 - -完成后必须提交一次独立 Git commit。 - ---- - -## Phase 2 — Shared Domain / Repository - -- [ ] 迁移 / 重构类型 -- [ ] 迁移 Demo 数据 -- [ ] 迁移 Repository Interface -- [ ] DemoRepository 双端可运行 -- [ ] StorageAdapter -- [ ] MediaAdapter 基础接口 - -完成后运行测试并提交。 - ---- - -## Phase 3 — Core Navigation - -按顺序: - -1. Welcome -2. Onboarding -3. Home -4. Search -5. Book Detail - -要求: - -- 页面跳转正确 -- 视觉基本一致 -- 小程序和 H5 都能运行 - ---- - -## Phase 4 — Publish - -- [ ] 图片选择 -- [ ] 草稿 -- [ ] 表单 -- [ ] Tobby 一键成文模拟 -- [ ] 预览 -- [ ] 发布成功状态 - -这是核心流程,必须单独验收。 - ---- - -## Phase 5 — Messages - -- [ ] 消息中心 -- [ ] 通知分类 -- [ ] 私聊列表 -- [ ] 聊天 -- [ ] 图片 -- [ ] 站内书籍链接 -- [ ] 未读状态 - ---- - -## Phase 6 — Profile / Management - -迁移当前 H5 已存在: - -- [ ] Profile -- [ ] Favorites -- [ ] My Listings -- [ ] Demo reset / management - -注意: - -新版 EXP / 粉丝 / About Tobby 暂不属于 parity 阶段。 - ---- - -## Phase 7 — State Pages - -迁移: - -- [ ] Loading -- [ ] Searching -- [ ] Empty -- [ ] No Results -- [ ] Network Error -- [ ] Maintenance -- [ ] Book Unavailable -- [ ] Published Successfully -- [ ] 404 - ---- - -## Phase 8 — 双端视觉与行为验收 - -H5: - -- [ ] 360px -- [ ] 390px -- [ ] 430px - -微信小程序: - -- [ ] 常见手机尺寸 -- [ ] Safe Area -- [ ] 底部导航 -- [ ] 滚动区域 -- [ ] 键盘顶起 -- [ ] 图片选择 -- [ ] 页面返回 -- [ ] 分享入口(即使暂为 stub) - ---- - -# 19. Golden Screenshot 回归方式 - -迁移期间建议同时运行: - -```text -Legacy H5 -Taro H5 -WeChat Mini Program -``` - -逐页比较: - -```text -legacy H5 @ 390px - vs -Taro H5 @ 390px - vs -WeApp Device Screenshot -``` - -允许平台导致的轻微字体 / 控件差异。 - -不允许: - -- 页面结构明显改变 -- 信息层级变化 -- 品牌色漂移 -- Tobby 被删除 -- 商品卡信息缺失 -- Bottom Nav 功能变化 - ---- - -# 20. 测试要求 - -当前已有 Repository 测试覆盖: - -- 组合筛选 -- 价格排序 -- 收藏持久化 -- 草稿 + 发布 -- 消息追加 - -迁移时: - -1. 尽量保留这些测试逻辑。 -2. 将纯业务测试迁移为平台无关测试。 -3. Platform Adapter 单独补最小测试。 -4. 不允许为了“让测试通过”删除关键断言。 - -每个阶段至少执行: - -```bash -lint -test -build:h5 -build:weapp -``` - -具体命令根据最终 Taro `package.json` 确定。 - ---- - -# 21. 每次提交建议 - -建议小步提交,例如: - -```text -chore: initialize taro dual-platform workspace -refactor: extract shared domain and repository contracts -feat: migrate welcome and onboarding to taro -feat: migrate home and search flows -feat: migrate publish flow and media adapter -feat: migrate messages and chat -feat: migrate profile and state pages -fix: align taro h5 visual parity at 390px -fix: align weapp safe-area and tab navigation -docs: complete taro migration notes -``` - -不要一个 commit 塞完整迁移。 - ---- - -# 22. 明确禁止事项 - -迁移阶段禁止 Agent: - -- 新建独立长期仓库 -- 删除 `web/` -- 强推 `main` -- 重写 Git 历史 -- 覆盖原始 `Assets/` -- 顺手重做整套 UI -- 用截图作为页面背景代替真实 UI -- 把全部页面继续塞进单个超级组件 -- 让共享业务代码直接依赖 `window` / `document` -- 为了跨端方便删除关键交互 -- 把真实 AI / 后端接入混进基础迁移 -- 擅自改变产品核心流程 - ---- - -# 23. Phase 2:迁移完成后才允许继续的新功能 - -Taro 基座完成并合并回主线之后,再继续开发: - -## 新版“我的” - -- EXP 经验条 -- 等级 -- 关注人数 -- 粉丝人数 -- 发布数量 -- 获赞数量 -- 更多个人工具栏 - -## 关于 Tobby - -- Tobby 的诞生理念 -- “托付”品牌解释 -- Tobby 小档案 -- 角色世界观 -- 彩蛋入口 - -## Tobby MBTI 投票 - -示例: - -```text -猜一猜 Tobby 是什么 MBTI? -ENFP -INFJ -INFP -ENFJ -其他 -``` - -属于轻量品牌彩蛋,不应影响主要交易流程。 - -## 真实 AI - -将: - -```text -DemoListingAssistant -``` - -替换为后端多模态服务。 - -## 真实 Backend - -将: - -```text -DemoRepository -``` - -替换 / 扩展为: - -```text -ApiRepository -``` - ---- - -# 24. 合并标准 - -只有同时满足以下条件,才允许将 `refactor/taro-migration` 合并回 `main`: - -- [ ] Taro H5 可构建 -- [ ] 微信小程序可构建 -- [ ] 核心页面完整 -- [ ] 当前 H5 主要业务闭环迁移完成 -- [ ] Repository 边界保留 -- [ ] Platform Adapter 已建立 -- [ ] 关键测试通过 -- [ ] H5 390px 视觉回归通过 -- [ ] 微信端基础真机 / 模拟器验证通过 -- [ ] 不存在明显横向溢出 -- [ ] 不存在严重 Safe Area 问题 -- [ ] 发布流程可完整走通 -- [ ] 搜索 / 筛选可完整走通 -- [ ] 聊天可完整走通 -- [ ] README 已更新 -- [ ] TODO 已更新 -- [ ] 迁移日志已记录 - ---- - -# 25. Agent 每次上下文压缩后的恢复流程 - -如果 Agent / Codex 发生上下文压缩或重新进入项目,必须先阅读: - -```text -TARO_MIGRATION_AGENT.md -TODO.md -README.md -``` - -然后检查: - -```bash -git status -git log --oneline -n 10 -``` - -再继续任务。 - -禁止仅依赖模型记忆猜测当前进度。 - ---- - -# 26. 最终目标架构 - -迁移结束后,BITerStore 应形成如下思维模型: - -```text - BITerStore - │ - Taro React Frontend - │ - ┌────────────────┴────────────────┐ - │ │ - Shared Core Platform Layer - │ │ - ┌─────┼─────┐ ┌───────┴───────┐ - │ │ │ │ │ -Books Users Messages WeApp H5 - │ │ │ login/share browser - └──── Repository ────┐ media/storage storage/share - │ - DemoRepository - │ - Future ApiRepository -``` - -项目的长期目标不是“同时维护两个前端”。 - -而是: - -> **一套产品、一套核心业务逻辑、一套设计系统,针对微信小程序和 H5 做最薄的平台适配。** - ---- - -# 27. 最重要的一句话 - -> **当前 H5 是基准,不是包袱;Taro 是新的正式前端基座,不是另一个产品。** - -迁移时优先保护已经完成的: - -- 产品闭环 -- 视觉体系 -- Tobby IP -- Repository 边界 -- 交互体验 -- 测试价值 - -先完成可靠迁移,再继续让 BITerStore 长新功能。 diff --git a/README.md b/README.md index 07abca9..ce8f085 100644 --- a/README.md +++ b/README.md @@ -138,6 +138,20 @@ npm test npm run build ``` +Taro 双端客户端: + +```bash +cd ../miniProgram +npm install +npm run dev:h5 +# 或构建微信小程序 +npm run build:weapp +``` + +微信开发者工具和自动化环境配置见 [`WEAPP_CODEX_AUTOMATION_SETUP.md`](./WEAPP_CODEX_AUTOMATION_SETUP.md)。旧 `web/` 在迁移期间继续作为视觉、交互和回滚基线。 + +当前锁定 Taro 4.2.1 的传递依赖仍有 npm audit 上游告警;H5 直接复用 `web/app/components/mobile-app.tsx` 与 Golden Reference CSS,生产入口约 357 KiB。它们不阻塞离线演示,但属于正式生产化前必须解决的升级与性能门禁;不要对 lockfile 执行不兼容的 `npm audit fix --force`。 + ## 🗂 项目结构 ```text @@ -145,6 +159,7 @@ BITerStore/ ├─ Assets/ # 原始设计参考与 Tobby 素材,不覆盖源文件 ├─ docs/avatars/ # 开发团队头像素材 ├─ qa-screenshots/ # 360 / 390 / 430px 浏览器验收截图 +├─ miniProgram/ # Taro 4.2.1 微信小程序与 H5 双端客户端 ├─ web/ │ ├─ app/ │ │ ├─ components/ # 页面与通用移动组件 diff --git a/TODO.md b/TODO.md index 5a3a467..cf89405 100644 --- a/TODO.md +++ b/TODO.md @@ -52,25 +52,55 @@ - [x] 完成公开前敏感信息审计,并重制含品牌封面、真机画廊、交互/架构图与快速开始的精美 README - [x] 在 README 结尾加入 StudentOP Aiden(前端)与 Smal_Young(后端)头像署名 - [x] 添加标准 Apache License 2.0,并同步 README 许可徽章与说明 +- [x] 调研 BIT101 前端、Go 后端、BIT-Login 及公开 API 的校园认证实现与许可证边界 +- [x] 完成小程序/H5 技术选型、后端架构、认证、治理及 8 周里程碑整体计划(`docs/整体实施计划.md`) +- [x] 完成早期 Taro 迁移成本验证;该次“停止迁移”结论已被 2026-08-26 的正式双端迁移决策覆盖 +- [x] 创建 `refactor/taro-migration` 并保留 `h5-prototype-v0.1` Golden Reference +- [x] 建立 Taro 4.2.1 + React 18.3.1 + TypeScript 5.4.5 + Webpack 5 双端工程 +- [x] 建立 Listing 领域模型、DemoRepository 与 Storage/Media/Navigation/Share/Feedback/Cache 适配器 +- [x] 迁移欢迎、引导、首页、搜索、详情、发布、消息、聊天、我的、收藏、我的发布和状态页 +- [x] 完成 Taro H5 与微信小程序生产构建、TypeScript、ESLint 和 6 项单测 +- [x] 合并云端 Taro 骨架,收敛并重命名为唯一 `miniProgram/` 客户端,移除临时原生 `miniapp/` +- [x] 以 `web/app/components/mobile-app.tsx` 和 `web/app/globals.css` 为唯一 Golden Reference;Taro H5 直接使用原组件和原 CSS,微信端只保留必要的平台组件映射,并将空白页/运行时异常纳入 H5 视觉门禁 ## 进行中 -- [ ] Taro Phase 1:完成 `miniProgram/` Taro React 双端骨架、品牌 App Shell 与页面路由 -- [ ] Taro Phase 2:迁移 Domain、DemoRepository、Storage/Media/Navigation 等平台适配器 -- [ ] Taro Phase 3:迁移欢迎、引导、首页、搜索和商品详情 -- [ ] Taro Phase 4:迁移图片、草稿、Tobby 一键成文、预览与发布闭环 -- [ ] Taro Phase 5:迁移通知、消息列表、聊天和未读状态 -- [ ] Taro Phase 6:迁移个人中心、收藏、发布管理和演示重置 -- [ ] Taro Phase 7:迁移完整状态页与 404 -- [ ] Taro Phase 8:完成 H5 / 微信小程序视觉、行为、自动化和真机验收 -- [ ] 建立微信开发者工具 CLI + `miniprogram-automator` + 受限 MCP 本地闭环 -- [ ] 建立 Taro H5 所有者私有 Sites 预览,验收后再决定是否替换现网 +### Taro 双端迁移 Phase 0–8 + +- [ ] Phase 0:开启微信开发者工具服务端口,使用 `miniProgram/` 完成 CLI/9420/automator 闭环验证 +- [x] Phase 1:Taro 骨架、双端构建、公共 touristappid 配置和版本锁定 +- [x] Phase 2:Listing Domain、Repository、平台适配器和独立存储命名空间 +- [x] Phase 3:首页、搜索、详情、发布、消息与个人中心核心流程 +- [x] Phase 4:状态页、旧 H5 路由转写和手机/平板/桌面响应式样式 +- [x] Phase 5:doctor、open、connect/launch E2E 和 qa 命令 +- [ ] Phase 6:在微信开发者工具运行核心 E2E,检查 route、结构、异常和截图 +- [ ] Phase 7:已完成 360/390/430/820/1280 精确视口 H5 视觉回归;待至少一台微信真机冒烟 +- [ ] Phase 8:用户确认后创建 owner-only Taro H5 私有预览;不替换正式 H5 + +### 已知依赖风险 + +- [ ] Taro 4.2.1 的锁定依赖树仍包含 npm audit 上游告警(含 Swiper、lodash-es、Vite/webpack-dev-server 等传递依赖);禁止 `--force` 绕过 Taro 的精确 peer 约束,生产化前需随 Taro 官方兼容版本升级并重新审计。 +- [ ] 直接复用 Golden Reference 后的 H5 生产入口约 357 KiB,演示交付可接受;正式上线前应继续拆包并建立性能预算。 ## 待完成 -- [ ] 微信开发者工具中确认账号登录并开启安全设置里的服务端口 -- [ ] 在 `miniProgram/project.private.config.json` 中保留真实 AppID,本文件不入 Git -- [ ] 合并前完成常见手机尺寸、小程序 Safe Area、键盘、媒体选择与返回栈真机验收 +### 生产化第 0 阶段:立项与关键验证 + +- [ ] 联系 BIT-Login/BIT101 维护团队,确认许可证或书面自托管许可、注册 JWT 配置和维护责任 +- [ ] 确认微信小程序主体、服务类目、备案 HTTPS 域名和隐私指引要求 +- [ ] 使用现有原型访谈/测试 10–20 名学生,验证找书、发布、联系和安全需求 +- [ ] 冻结 MVP 范围、数据字典、商品状态机、验收指标与团队负责人 +- [x] 完成 Taro React 迁移成本验证并正式重启双端迁移;旧 H5 保留为 Golden Reference +- [ ] 部署加固后的 BIT-Login 专用实例,只开放认证路由并收紧 CORS、网关与限流 +- [ ] 完成一次不写业务数据库的 challenge → registration JWT → BITerStore 后端验签技术验证 +- [ ] 完成原 H5 在 360–430px 真机上的视觉、分享、图片选择和返回栈验收 +- [ ] 部署原 H5 到正式 HTTPS 域名;若仍需微信小程序入口,再评估合规的 `web-view` 壳与业务域名配置 + +### 生产化实施(第 0 阶段通过后启动) + +- [ ] 初始化小程序客户端、共享 contracts、服务端、管理后台和 CI/CD +- [ ] 实现微信会话、校园认证、商品、图片、搜索、收藏、聊天、举报和治理闭环 +- [ ] 完成隐私合规、安全测试、备份恢复、封闭灰度和小程序提审 ## 固定要求 @@ -81,3 +111,4 @@ - 每次上下文自动压缩后,必须先重新阅读本文件再继续。 - Taro 迁移期间保留现有 `web/`,不得删除、重命名或用 Taro 中间状态覆盖其部署。 - 微信端禁止自动上传、提审、发布、修改 AppID 或配置 `miniprogram-ci`。 +- 正式双端客户端目录唯一为 `miniProgram/`;不得再次引入并行的 `taro/` 或原生 `miniapp/` 工程。 diff --git a/WEAPP_CODEX_AUTOMATION_SETUP.md b/WEAPP_CODEX_AUTOMATION_SETUP.md new file mode 100644 index 0000000..7e38935 --- /dev/null +++ b/WEAPP_CODEX_AUTOMATION_SETUP.md @@ -0,0 +1,34 @@ +# 微信开发者工具自动化设置 + +## 一次性准备 + +1. 使用微信开发者账号登录开发者工具。 +2. 打开“设置 → 安全设置 → 服务端口”。Agent 不会代为修改此设置。 +3. 在 `miniProgram/` 复制 `.env.example` 为 `.env.weapp.local`,填写开发者工具显示的 HTTP 服务端口。 +4. 如需真机调试,在忽略提交的 `miniProgram/project.private.config.json` 中配置本机真实 AppID;公共 `project.config.json` 始终使用 `touristappid`。 + +本机 Node 位于 `F:\BITerstore\.tools\node-v22.13.1-win-x64`。若未加入 PATH,可在 PowerShell 当前会话执行: + +```powershell +$env:Path='F:\BITerstore\.tools\node-v22.13.1-win-x64;'+$env:Path +``` + +## 检查与运行 + +```powershell +cd F:\BITerstore\app\miniProgram +npm run weapp:doctor +npm run build:weapp:e2e +npm run e2e:weapp:launch +``` + +- DevTools HTTP 服务端口来自安全设置,用于 CLI 调用。 +- `9420` 是 automator WebSocket 端口,二者不能混用。 +- `e2e:weapp:connect` 连接已运行的 9420 会话;`e2e:weapp:launch` 自行启动并在结束时关闭。 +- 失败证据写入 `miniProgram/qa-artifacts/`,该目录不会提交。 + +## 安全边界 + +- 禁止运行上传、预览上传、提审或发布命令。 +- 禁止提交真实 AppID 私有覆盖、CLI token、端口、登录二维码和用户数据。 +- 社区 MCP 仅可在仓库 E2E 通过后另行评估,不是当前必要依赖。 diff --git "a/docs/\346\225\264\344\275\223\345\256\236\346\226\275\350\256\241\345\210\222.md" "b/docs/\346\225\264\344\275\223\345\256\236\346\226\275\350\256\241\345\210\222.md" new file mode 100644 index 0000000..b8eecd8 --- /dev/null +++ "b/docs/\346\225\264\344\275\223\345\256\236\346\226\275\350\256\241\345\210\222.md" @@ -0,0 +1,510 @@ +# BITerStore 校内二手书交易平台整体实施计划 + +> 当前决策(2026-08-26):正式重启 Taro 双端迁移,以 `miniProgram/` 作为微信小程序与 H5 的唯一新客户端;现有 `web/` H5 保留为 Golden Reference 和回滚版本。 + +> 文档版本:v0.1 +> 制定日期:2026-08-25 +> 当前阶段:纯前端交互原型已完成,准备进入产品验证、认证对接与工程化实施阶段 + +## 1. 结论先行 + +BITerStore 第一阶段应被定义为:**仅面向北京理工大学已认证成员、以信息撮合和校内当面交易为核心、不承接线上支付的二手书平台**。 + +建议采用以下路线: + +1. 保留当前 `web/` React 原型,作为产品需求、视觉规范和交互验收基线。 +2. 正式客户端新建 **Taro + React + TypeScript** 工程,优先发布微信小程序,同时保留编译 H5 的能力。 +3. 新建独立后端,采用“模块化单体”而非一开始拆微服务;共用一套 API 服务于小程序和 H5。 +4. 校园身份认证必须通过 BIT101/学校授权的认证服务完成;BITerStore 不保存学校统一身份认证密码,也不自行模拟或抓取学校登录流程。 +5. MVP 不做在线支付、物流、评价体系、AI 识别和复杂推荐。先验证“有书可找、发布够快、能安全联系、交易能闭环”。 + +推荐的最终形态不是简单的 H5 套壳。`web-view` 可以用于早期内测或承载少量辅助页面,但不应作为小程序首页、发布、聊天等主流程的长期方案。 + +## 2. 已有资产与现状判断 + +### 2.1 当前前端 + +现有仓库已经具备一个完成度较高的 React 19 + TypeScript 移动端原型,主要能力包括: + +- 首页、分类、搜索、组合筛选和商品详情; +- 图片上传、发布、草稿恢复和发布预览; +- 收藏、我的发布、消息中心和聊天演示; +- Loading、Empty、Error、Maintenance、404 等完整状态; +- 360px、390px、430px 移动端适配; +- `DemoRepository` 数据边界、本地持久化、单元测试和 Service Worker; +- 已建立的品牌、Design Tokens、Tobby 角色和视觉资产。 + +它目前仍是**纯前端演示系统**:数据主要在 LocalStorage/IndexedDB 中,默认用户已认证,没有真实账户、后端、内容审核、实时聊天和生产安全能力。 + +### 2.2 BIT101 与 BIT-Login 可复用内容 + +BIT101 的公开前端和 Go 后端展示了两代相关流程: + +- 旧流程:WebVPN 初始化、统一身份验证、邮件验证、注册,登录后通过 JWT 形式的 `fake-cookie` 鉴权; +- 较新前端:调用独立登录服务,以 challenge、短期 access token 和短信二次验证完成教务相关身份认证。 + +`BIT101-dev/BIT-Login` 当前主分支则已经提供较完整的 Kotlin/Ktor 认证服务:异步 challenge、短信二次验证、短期 session,以及面向指定 `audience` 签发的 Ed25519 注册 JWT。它可以作为 BITerStore 的校园认证适配器,优先使用 `/api/auth/*` 与 `/registration-token`,无需复制旧版 WebVPN 实现。 + +但它不是学校官方 OAuth/OIDC 服务,生产使用前仍需完成以下确认和加固: + +- 当前仓库根目录未发现明确的 `LICENSE` 文件,公开可读不等于允许复制、修改和部署;应请维护者补充许可证或给予书面许可; +- 默认 CORS 配置使用 `anyHost()`,生产实例必须改为域名白名单; +- 服务同时暴露成绩、课程、Cookie 等接口,BITerStore 专用实例应通过代码或网关只开放 `/api/auth/*` 和健康检查; +- 确认部署责任、上游认证变化、故障联络、限流以及用户凭据处理披露。 + +BIT101 前后端采用 AGPL-3.0,当前 BITerStore 前端采用 Apache-2.0。可以参考其公开设计和文档;若复制、修改或部署其代码,必须先做许可证兼容性评估,不能默认保持 BITerStore 原有许可不变。 + +## 3. 客户端方案选择 + +| 方案 | 研发速度 | 小程序体验 | 复用现有前端 | 长期维护 | 结论 | +| --- | --- | --- | --- | --- | --- | +| 继续现有 H5 | 最快 | 用户需从浏览器进入 | 最高 | 双端能力弱 | 可用于封闭内测 | +| 小程序 `web-view` 套 H5 | 较快 | 登录、导航、分享、文件能力存在割裂 | 高 | 容易形成平台边界问题 | 只作临时过渡 | +| 原生微信小程序 | 较慢 | 最佳 | 很低 | 单端维护清晰 | 团队只做微信时可选 | +| Taro React:微信小程序 + H5 | 中等 | 接近原生 | 可复用 React 思维、类型和部分业务代码,不能直接复用 DOM 页面 | 一套业务核心支持两端 | **推荐** | + +### 推荐落地方式 + +采用渐进迁移,而不是直接改造当前 `web/`: + +```text +BITerStore/ +├─ web/ # 现有原型,继续作为 UI/交互基准与内测 H5 +├─ clients/ +│ └─ miniProgram/ # Taro React,输出 weapp 与 h5 +├─ packages/ +│ ├─ contracts/ # API DTO、状态枚举、校验规则 +│ ├─ design-tokens/ # 色彩、字号、圆角、间距 +│ └─ domain/ # 无平台依赖的业务逻辑 +├─ server/ # 独立后端 +├─ admin/ # 最小化治理后台 +└─ docs/ +``` + +迁移时可以复用:产品信息架构、文案、图片资产、Design Tokens、TypeScript 类型、种子数据和部分纯业务函数。不能预期直接复用:Next/Vinext 路由、浏览器 DOM 组件、LocalStorage/IndexedDB、Service Worker 和依赖浏览器 API 的 CSS/动画。 + +若团队必须在 4 周内让真实用户试用,可先发布 HTTPS H5 内测;但此阶段仍要使用真实后端,不能继续用本地演示数据。完成关键数据验证后再发布 Taro 小程序。 + +### 可采用的开源小程序框架 + +可以使用其他开源框架,但应该选择“维护活跃、许可证明确、团队技术栈匹配”的基础框架,不建议直接套一个来源不明的二手商城成品项目。 + +| 开源方案 | 主要技术 | 优点 | 对本项目的代价 | 建议 | +| --- | --- | --- | --- | --- | +| [Taro](https://github.com/NervJS/taro) | React/Vue、MIT | 支持微信小程序与 H5;与现有 React/TypeScript 团队最接近 | 仍需重写 DOM、路由和浏览器存储层 | **首选** | +| [uni-app](https://github.com/dcloudio/uni-app) | Vue、Apache-2.0 | 多端生态和插件丰富,上手资料多 | 团队需从 React 切到 Vue;现有组件复用更少 | 团队更熟 Vue 时选择 | +| [Mpx](https://github.com/didi/mpx) | 增强小程序 DSL | 小程序能力和性能优化较深入 | 社区规模与团队熟悉度需单独验证 | 有既有 Mpx 经验时选择 | +| [微信原生示例](https://github.com/wechat-miniprogram/miniprogram-demo) + 原生框架 | WXML/WXSS/JS/TS | 平台能力最直接、依赖最少 | H5 需要单独实现,现有 React 复用最低 | 确定只做微信小程序时选择 | + +最终选型用一个 2 天 spike 决定:分别验证商品长列表、图片上传、登录 challenge、底部导航、分享和 360–430px 真机效果。若没有明显阻断项,沿用 Taro React,避免仅因“还有其他开源项目”而更换技术栈。 + +## 4. 产品范围 + +### 4.1 MVP 必须完成 + +- 校园身份认证、微信身份绑定、登录与注销; +- 浏览、关键词搜索、分类和校区筛选; +- 商品详情、收藏; +- 发布、编辑、下架、重新上架、标记预留/已售; +- 文本会话、未读数、系统通知; +- 举报商品/用户、拉黑、违规内容处置; +- 我的发布、我的收藏、会话和基础个人资料; +- 最小管理后台:用户、商品、举报、封禁、审计日志; +- 用户协议、隐私政策、交易安全提示、账号注销与数据删除入口; +- 监控、备份和基础运营指标。 + +### 4.2 MVP 明确不做 + +- 在线支付、担保交易、退款和平台抽成; +- 快递/跑腿履约; +- 竞价、复杂订单、优惠券、积分和会员体系; +- 公布手机号、精确宿舍或实时位置; +- 图片消息、语音、群聊和音视频; +- AI 自动识书、个性化推荐和复杂搜索集群; +- 扩展到数码、代购、票务等高风险品类。 + +### 4.3 核心业务闭环 + +```mermaid +flowchart LR + A[微信进入] --> B[微信会话] + B --> C[校园身份认证] + C --> D[浏览 / 搜索] + D --> E[商品详情] + E --> F[站内联系] + F --> G[卖家设为预留] + G --> H[校内当面验货交易] + H --> I[卖家标记已售] + + C --> J[发布书籍] + J --> K[审核 / 风控] + K --> D +``` + +## 5. 认证与账户设计 + +### 5.1 两类身份必须分开 + +- **微信身份**:用于识别当前小程序设备/微信用户和建立应用会话;`wx.login` 只能证明微信侧身份,不能证明其为北理学生。 +- **校园身份**:用于授予“北理认证”资格,必须来自学校或 BIT101 明确授权的可信认证结果。 + +数据库中将两者绑定到一个 BITerStore 用户,而不是把学号直接当作主键。 + +### 5.2 确定方案:BIT-Login 注册 JWT + +在取得使用许可后,部署 BITerStore 专用的 BIT-Login 实例,采用以下接口: + +1. `POST /api/auth/start`:提交学号、统一认证密码和所需服务,创建 challenge; +2. `GET /api/auth/{challenge_id}`:轮询 `running / waiting_sms / authenticated / failed / expired`; +3. `POST /api/auth/{challenge_id}/sms`:需要时提交短信验证码; +4. `POST /api/auth/{challenge_id}/registration-token`:认证成功后,为 `audience=biterstore` 签发短期 Ed25519 JWT; +5. `DELETE /api/auth/{challenge_id}`:BITerStore 完成注册/绑定后立即销毁 challenge 和关联会话。 + +BITerStore 后端仅信任 registration token,不接收学校密码、短信码或教务 Cookie。它必须验证 JWT 的 Ed25519 签名、`iss`、`aud=biterstore`、`exp`、`iat`、`purpose=registration`、`sub` 和 `jti`,并将 `jti` 作为一次性凭证消费,防止重放。 + +BIT-Login 只用于证明校园身份,不调用或保存成绩、课表、学分等与交易无关的数据。学校邮箱验证码可作为认证服务长时间中断时的人工审核备选,但不得静默等同于完整统一身份认证。 + +### 5.3 推荐登录流程 + +```mermaid +sequenceDiagram + participant M as 小程序 + participant B as BITerStore 后端 + participant W as 微信接口 + participant I as BIT-Login 专用实例 + + M->>B: wx.login 临时 code + B->>W: code2Session(仅服务端调用) + W-->>B: openid / session_key + B-->>M: 未认证的短期应用会话 + M->>I: /api/auth/start(仅本次使用学校凭据) + I-->>M: challenge_id + challenge token + M->>I: 轮询状态;需要时提交短信码 + I-->>M: authenticated + M->>I: 申请 audience=biterstore 的 registration JWT + I-->>M: 5 分钟短期 JWT + M->>B: 提交 registration JWT + B->>B: 验签、校验 claims、单次消费 jti + B-->>M: 已认证的 access token + refresh token + M->>I: 删除 challenge +``` + +### 5.4 最小化存储 + +建议仅保存: + +- 内部 `user_id`; +- 微信 `openid`(如确有跨应用需求再评估 `unionid`); +- 认证方 `issuer` 与不可逆/稳定的外部主体标识; +- 校园认证状态、认证时间、到期时间; +- 用户主动填写的昵称、头像、校区。 + +默认不保存:统一身份认证密码、WebVPN Cookie、短信验证码、教务 Cookie、成绩、课程表、身份证号。若业务确需保存学号,应先论证必要性,并做字段级加密、访问审计和展示脱敏。 + +## 6. 技术架构 + +### 6.1 总体结构 + +```mermaid +flowchart TB + MP[微信小程序 / Taro] --> API[HTTPS API 网关] + H5[H5 / Taro] --> API + ADM[管理后台] --> API + API --> APP[模块化业务服务] + APP --> PG[(PostgreSQL)] + APP --> REDIS[(Redis,可按需启用)] + APP --> OSS[(对象存储)] + APP --> AUTH[BIT101 / 学校认证] + APP --> MSG[WebSocket / 消息通道] + APP --> OBS[日志、指标、告警] +``` + +### 6.2 后端建议 + +第一阶段使用模块化单体: + +- 推荐栈:团队熟悉 TypeScript 时使用 NestJS/Fastify;熟悉 Go 时使用 Gin。两者都可满足 MVP,团队能力比框架偏好更重要。 +- API:REST;实时聊天使用 WebSocket。若早期部署环境不稳定,可先用 5–10 秒增量轮询。 +- 数据库:PostgreSQL,作为唯一事实来源。 +- 搜索:MVP 先使用 PostgreSQL 全文搜索/模糊匹配和规范化 ISBN;数据量或相关性出现瓶颈后再引入 Meilisearch。 +- 缓存与限流:初期可用进程内限流;多实例或消息规模上升后启用 Redis。 +- 图片:S3 兼容对象存储,客户端直传临时凭证/签名 URL,服务端记录元数据并执行格式、大小和内容检查。 +- 校园认证:隔离部署 BIT-Login Ktor 服务;网关只允许必要认证路由,SQLite 放持久化加密磁盘,注册私钥独立保管。 +- 部署:中国大陆 HTTPS 域名、自动化构建、数据库迁移、每日备份;正式上线前确认 ICP、校方和小程序主体/类目要求。 + +不要在 MVP 直接照搬 BIT101 的 PostgreSQL + Redis + Meilisearch + Gorse 全套部署;交易平台初期的数据规模不需要推荐系统,额外组件会显著增加运维成本。 + +## 7. 核心数据模型 + +| 实体 | 关键字段 | +| --- | --- | +| `users` | id、nickname、avatar、campus、status、created_at | +| `identities` | user_id、provider、external_subject、verified_at、expires_at | +| `wechat_accounts` | user_id、openid、unionid_nullable、last_login_at | +| `sessions` | user_id、refresh_token_hash、device、expires_at、revoked_at | +| `listings` | seller_id、title、isbn、author、category、condition、price、campus、description、status | +| `listing_images` | listing_id、object_key、sort_order、moderation_status | +| `favorites` | user_id、listing_id、created_at,联合唯一约束 | +| `conversations` | listing_id、buyer_id、seller_id、last_message_at | +| `messages` | conversation_id、sender_id、type、content、created_at、read_at | +| `reports` | reporter_id、target_type、target_id、reason、evidence、status | +| `blocks` | user_id、blocked_user_id、created_at | +| `moderation_actions` | operator_id、target、action、reason、created_at | +| `audit_logs` | actor、action、resource、request_id、created_at | + +商品状态统一为: + +```text +DRAFT → PENDING_REVIEW → ACTIVE → RESERVED → SOLD + ↘ OFF_SHELF + ↘ BLOCKED +``` + +关键约束:价格使用整数分;删除优先软删除;状态变更使用乐观锁;收藏、会话和幂等请求建立唯一约束;卖家不能联系或收藏自己的商品。 + +## 8. API 分组 + +```text +POST /v1/auth/wechat/session +POST /v1/auth/campus/start +POST /v1/auth/campus/callback +POST /v1/auth/refresh +POST /v1/auth/logout +GET /v1/me +PATCH /v1/me +DELETE /v1/me + +GET /v1/listings +POST /v1/listings +GET /v1/listings/:id +PATCH /v1/listings/:id +POST /v1/listings/:id/state +POST /v1/listings/:id/favorite +DELETE /v1/listings/:id/favorite + +POST /v1/uploads/presign +POST /v1/uploads/:id/complete + +GET /v1/conversations +POST /v1/conversations +GET /v1/conversations/:id/messages +POST /v1/conversations/:id/messages +POST /v1/conversations/:id/read + +POST /v1/reports +POST /v1/blocks/:userId +GET /v1/notifications +``` + +所有写接口应具备:身份校验、对象级权限检查、输入校验、限流、幂等策略、结构化审计日志和统一错误码。前后端通过 OpenAPI 生成类型或共享 `contracts`,不手工维护两套接口类型。 + +## 9. 安全、隐私与平台治理 + +### 9.1 安全底线 + +- 全站 HTTPS,密钥通过部署环境管理,不进入 Git; +- access token 短期有效,refresh token 轮换并只存哈希; +- 小程序令牌通过授权头传输;H5 优先使用 `HttpOnly + Secure + SameSite` Cookie; +- 密码、学校 Cookie 和微信 `session_key` 不发给客户端、不写日志; +- 图片校验 MIME、扩展名、尺寸、容量,重新编码后再公开; +- 登录、发布、私信、举报均做分层限流和异常告警; +- 对越权、批量爬取、刷屏、SQL 注入、XSS、CSRF、SSRF、恶意文件上传做专项测试; +- 管理员启用强认证,所有处置动作留审计记录。 +- BIT-Login 强制 HTTPS、来源白名单和速率限制;关闭或拦截成绩、Cookie、课程等无关路由;challenge 数据按最短期限清理。 + +### 9.2 隐私原则 + +依据最小必要原则,只收集完成功能所需信息;明确告知处理目的、保存期限和第三方共享情况;提供查阅、更正、注销和删除渠道。校园认证信息与公开资料分离,默认只展示“已认证”徽章,不公开学号、真实姓名、手机号或具体宿舍。 + +### 9.3 交易和内容治理 + +- 上线前由校方/法律顾问确认平台主体责任、用户协议和交易规则; +- 仅允许书籍,建立禁售清单:盗版、内部涉密材料、非法出版物、含个人信息的资料等; +- 商品详情明确“平台仅提供信息撮合,建议校内公共场所当面验书”; +- 举报入口必须在商品、用户和会话中可达; +- 建立举报受理时限、申诉、封禁、证据留存和紧急下架流程; +- 平台是否构成电子商务平台、实名核验和信息报送义务,应在公测前取得专业判断,不能仅因“不做支付”而忽略平台责任。 + +## 10. 管理后台与运营 + +管理后台不是上线后的附加项,MVP 至少需要: + +- 待审核/被举报商品列表; +- 用户状态、认证状态和风险记录; +- 商品下架、用户禁言/封禁、申诉恢复; +- 举报工单流转和处置备注; +- 敏感操作二次确认和审计日志; +- 基础指标看板。 + +首批关注指标: + +- 校园认证成功率、失败原因和耗时; +- 新用户首日发布率; +- 搜索有结果率、商品详情到发起会话转化率; +- 发布完成率和平均发布时间; +- 7/30 日有效商品数、预留率、已售率; +- 举报率、处置时长、封禁率; +- API 错误率、P95 延迟、消息到达率。 + +不要把注册量、PV 当成唯一成功指标。MVP 的北极星指标建议采用:**每周完成的有效校内交易数**,由“双方确认完成”或卖家标记已售并结合会话行为估算。 + +## 11. 分阶段实施计划 + +以下按 3–4 名兼职学生开发者估算,共约 8 周。若认证协调或小程序资质尚未完成,时间应顺延,而不是绕过认证上线。 + +### 第 0 阶段:立项与关键验证(第 1 周) + +- 明确产品负责人、技术负责人、治理负责人和校方联系人; +- 联系 BIT-Login/BIT101 团队,完成使用许可、认证边界、测试环境和维护责任确认; +- 确认小程序主体、服务类目、域名备案、隐私指引和发布资质; +- 用 10–20 名同学访谈验证找书、卖书、联系和安全痛点; +- 冻结 MVP 范围、数据字典、状态机和验收指标; +- 产出认证技术验证 Demo,不接业务数据库。 + +**退出条件**:BIT-Login 许可证/书面许可明确,专用实例通过安全验证;小程序资质路线明确;团队接受 MVP 边界。 + +### 第 1 阶段:工程骨架(第 2 周) + +- 初始化 Taro 客户端、后端、共享 contracts 和 CI; +- 建立 PostgreSQL schema、迁移、种子数据和本地开发环境; +- 建立错误码、日志、request ID、配置管理和 API 文档; +- 将 Design Tokens 和核心资产迁入小程序; +- 搭建最小管理后台骨架。 + +**退出条件**:测试环境可自动部署;小程序和 H5 能调用健康检查及演示 API。 + +### 第 2 阶段:账户与校园认证(第 3 周) + +- 完成微信会话、校园认证、账户绑定、刷新、注销; +- 实现认证失败、短信二次验证、服务维护和过期重认证状态; +- 完成隐私授权、用户协议、账号删除和会话撤销; +- 对认证接口做重放、越权、过期和日志泄露测试。 + +**退出条件**:测试用户能够完成首次认证和再次登录;系统不保存学校密码/Cookie。 + +### 第 3 阶段:商品主链路(第 4–5 周) + +- 完成图片上传、商品 CRUD、审核状态和状态机; +- 迁移首页、分类、搜索、详情、收藏和我的发布; +- 完成价格、ISBN、校区、成色和描述校验; +- 接入基础内容安全与人工复核; +- 做搜索索引、分页、并发更新和上传失败恢复测试。 + +**退出条件**:真实用户可以发布、找到、收藏和管理商品;不存在客户端伪造卖家身份的问题。 + +### 第 4 阶段:联系与交易闭环(第 6 周) + +- 完成一物一买卖双方会话、文本消息、已读和未读数; +- 完成预留、取消预留、已售和重新上架; +- 完成拉黑、举报、系统通知和公共场所交易提示; +- 处理断线重连、消息幂等、顺序和重复发送。 + +**退出条件**:从商品详情到沟通、预留和已售可以完整走通。 + +### 第 5 阶段:治理、测试与灰度(第 7 周) + +- 补全管理后台和处置 SOP; +- 单元测试、API 集成测试、关键 E2E 和安全测试; +- 进行数据库备份恢复演练、认证服务故障演练; +- 20–50 名认证用户封闭测试,收集指标和问题; +- 修复阻断级问题并完成隐私/合规检查。 + +**退出条件**:无 P0/P1 缺陷;举报可闭环;备份可恢复;核心指标可观测。 + +### 第 6 阶段:小范围上线(第 8 周) + +- 微信小程序提审并准备审核补充材料; +- 按校区或学院逐步放量,不一次全校推广; +- 建立值班、告警、用户反馈和紧急下线机制; +- 上线后一周只修稳定性和安全问题,不扩需求; +- 根据有效交易数、供给密度和举报率决定是否扩大范围。 + +## 12. 测试与上线门槛 + +### 功能门槛 + +- 认证、发布、搜索、详情、会话、预留/已售、举报全部具备 E2E; +- 关键写操作支持重试且不产生重复数据; +- 商品状态和权限在服务端强制校验; +- 360–430px 小程序真机和主流微信版本通过验收。 + +### 性能与可靠性门槛 + +- 核心读取 API P95 小于 500ms(不含外部认证); +- 图片经过压缩与缩略图处理,弱网可展示占位和重试; +- 认证服务不可用时不影响已认证用户浏览已有内容; +- 数据库每日备份,至少完成一次恢复演练; +- 关键错误、登录异常、内容风险和管理员操作可追踪。 + +### 安全与合规门槛 + +- 仓库和构建物无密钥、Cookie、真实学号和个人测试数据; +- 完成权限矩阵、数据保留期限和第三方清单; +- 用户可注销,刷新令牌和关联会话随之撤销; +- 隐私政策、用户协议、交易规则、举报与申诉路径已上线; +- 校方/BIT101 接口授权、小程序资质和许可证评估均有记录。 + +## 13. 主要风险与应对 + +| 风险 | 影响 | 应对 | +| --- | --- | --- | +| BIT-Login 无明确许可证或维护承诺 | 无法合法部署或登录不稳定 | 第 0 周取得书面许可/补充许可证;自托管、监控并保留学校认可的替代方案 | +| BIT-Login 默认暴露无关接口与宽松 CORS | 凭据、Cookie 或教务数据风险 | 专用实例只开放认证路由,收紧 CORS、网关、限流和日志 | +| 学校认证流程变化或要求短信 | 登录中断 | challenge 状态机、超时/重试、维护页、服务端可观测性 | +| 现有 React 原型无法直接编译成小程序 | 迁移延期 | 以页面为单位迁移,先共享 contracts/domain/tokens,不承诺 DOM 代码零成本复用 | +| 小程序主体、类目或域名资质不足 | 无法提审 | 立项时同步推进,不等开发结束后才处理 | +| 书源不足、搜索总为空 | 用户流失 | 按学院/课程定向冷启动,先建设供给再扩大用户 | +| 私聊诈骗或线下安全事件 | 信任和责任风险 | 校园认证、站内沟通、拉黑举报、公共地点提醒、治理 SOP | +| 盗版和违规资料 | 法律/校方风险 | 禁售规则、图片/文本审核、快速下架与申诉 | +| 过早引入支付或综合品类 | 范围和合规失控 | MVP 明确只做书和线下交易,达到阶段指标后再立项评估 | +| 直接复制 AGPL 代码 | 许可证义务不清 | 仅以接口和思想作参考;复制或派生前做专项许可证评估 | + +## 14. 团队分工建议 + +- 产品/设计:需求边界、流程、Design Tokens、文案、可用性测试; +- 小程序前端:Taro 页面迁移、平台 API、状态管理、性能与真机适配; +- 后端:认证、数据模型、API、消息、对象存储、部署和监控; +- 治理/运营:校方沟通、认证授权、规则、审核、冷启动和反馈; +- 全员共同负责:接口评审、隐私检查、E2E 验收和上线值班。 + +每周只维护一份可交付看板,任务必须带负责人、验收条件和截止日期。架构决策以 ADR 记录,特别是认证协议、客户端技术栈、令牌存储、内容审核和许可证决策。 + +## 15. 立刻可执行的下一步 + +1. 由一名团队成员联系 BIT-Login/BIT101 维护者,确认许可证或取得书面部署许可。 +2. 确认团队能否取得微信小程序主体、所需服务类目和已备案 HTTPS 域名。 +3. 用现有原型对 10–20 名学生做任务测试,记录发布一本书、找到教材和联系卖家的完成率。 +4. 创建 `contracts`,先冻结 `User`、`Listing`、`Conversation`、`Report` 和商品状态枚举。 +5. 做两个限时技术验证:Taro 迁移一个商品列表页;通过 BIT-Login 完成一次不落业务库的 challenge → registration JWT → 验签流程。 +6. 技术验证通过后,再开始后端 schema 和全量页面迁移。 + +### 向 BIT-Login/BIT101 团队确认的问题 + +- 当前仓库采用什么许可证?是否允许 BITerStore 修改并自托管专用实例? +- `biterstore` 是否可以加入 `REGISTRATION_JWT_ALLOWED_AUDIENCES`?注册 JWT 的 `issuer`、`kid` 和公钥如何分发/轮换? +- `sub` 是否保证为本次成功认证的统一身份账号,是否可提供不暴露学号的稳定匿名主体? +- registration JWT 是否计划增加 JWKS、撤销或更明确的版本兼容机制? +- 是否支持小程序环境,域名是否可加入 request 合法域名,是否存在 CORS/Referer 限制? +- 自托管实例是否可只保留认证路由,关闭成绩、Cookie、课表等业务接口? +- 是否有上游变更通知、版本策略、已知风控限制和维护联系人? +- BIT-Login 如何处理和暂存密码、短信码、学校 Cookie/session,BITerStore 需要向用户披露哪些事项? + +## 16. 参考资料 + +- [BIT101 前端仓库](https://github.com/BIT101-dev/BIT101):Vue3 前端、统一身份认证入口和登录服务调用参考。 +- [BIT101 Go 后端](https://github.com/BIT101-dev/BIT101-GO):旧版 WebVPN 验证、JWT `fake-cookie` 和服务端部署参考。 +- [BIT101 API 文档](https://bit101-api.apifox.cn/):用户、上传、消息等接口的公开说明。 +- [BIT-Login](https://github.com/BIT101-dev/BIT-Login):Kotlin/Ktor challenge、短信二次验证和 Ed25519 registration JWT 实现。 +- [BITerStore 当前前端](https://github.com/AnonymousUser443/BITerStore):现有移动端产品原型和视觉基线。 +- [Taro 官方文档](https://docs.taro.zone/docs/):React、多小程序平台与 H5 的跨端开发能力。 +- [uni-app](https://github.com/dcloudio/uni-app):基于 Vue 的多端框架备选。 +- [Mpx](https://github.com/didi/mpx):增强型跨端小程序框架备选。 +- [微信小程序 `wx.login` 文档](https://developers.weixin.qq.com/miniprogram/dev/api/open-api/login/wx.login.html):微信登录临时凭证。 +- [微信小程序 `code2Session` 文档](https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/user-login/code2Session.html):服务端交换微信会话信息。 +- [微信小程序 `web-view` 文档](https://developers.weixin.qq.com/miniprogram/dev/component/web-view.html):H5 嵌入小程序时的平台边界。 +- [《中华人民共和国个人信息保护法》](https://www.cac.gov.cn/2021-08/20/c_1631050028355286.htm):个人信息处理、最小必要和用户权利要求。 +- [《中华人民共和国电子商务法》](https://www.samr.gov.cn/wljys/gzzd/art/2023/art_3e75434c954b4cb9bd14867dacff26d1.html):平台经营者、身份核验和平台治理相关义务。 + +--- + +本计划的第一个硬门槛不是“开始写后端”,而是**确认合法、稳定、最小化的校园认证路径**。认证、主体资质和治理责任明确后,现有原型已经足以支撑快速进入真实 MVP 开发。 diff --git a/miniProgram/.editorconfig b/miniProgram/.editorconfig new file mode 100644 index 0000000..5760be5 --- /dev/null +++ b/miniProgram/.editorconfig @@ -0,0 +1,12 @@ +# http://editorconfig.org +root = true + +[*] +indent_style = space +indent_size = 2 +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/miniProgram/.env.example b/miniProgram/.env.example new file mode 100644 index 0000000..44e17c7 --- /dev/null +++ b/miniProgram/.env.example @@ -0,0 +1,5 @@ +WECHAT_DEVTOOLS_CLI=D:\Program Files (x86)\Tencent\微信web开发者工具\cli.bat +WEAPP_PROJECT_PATH=F:\BITerstore\app\miniProgram +WECHAT_DEVTOOLS_SERVICE_PORT= +WEAPP_AUTOMATION_PORT=9420 +WECHAT_DEVTOOLS_CLI_TOKEN= diff --git a/miniProgram/.env.weapp.example b/miniProgram/.env.weapp.example deleted file mode 100644 index 3de8857..0000000 --- a/miniProgram/.env.weapp.example +++ /dev/null @@ -1,6 +0,0 @@ -WECHAT_DEVTOOLS_CLI=D:\Program Files (x86)\微信web开发者工具\cli.bat -WEAPP_PROJECT_PATH=D:\path\to\BITerStore\miniProgram -WECHAT_DEVTOOLS_SERVICE_PORT= -WEAPP_AUTOMATION_PORT=9420 -# Optional. Prefer setting this in the shell instead of committing a value. -WECHAT_DEVTOOLS_CLI_TOKEN= diff --git a/miniProgram/.eslintrc b/miniProgram/.eslintrc new file mode 100644 index 0000000..7809e66 --- /dev/null +++ b/miniProgram/.eslintrc @@ -0,0 +1,7 @@ +{ + "extends": ["taro/react"], + "rules": { + "react/jsx-uses-react": "off", + "react/react-in-jsx-scope": "off" + } +} diff --git a/miniProgram/.gitignore b/miniProgram/.gitignore new file mode 100644 index 0000000..bc64557 --- /dev/null +++ b/miniProgram/.gitignore @@ -0,0 +1,8 @@ +dist/ +deploy_versions/ +.temp/ +.rn_temp/ +node_modules/ +.DS_Store +.swc +*.local diff --git a/miniProgram/.node-version b/miniProgram/.node-version deleted file mode 100644 index 2bd5a0a..0000000 --- a/miniProgram/.node-version +++ /dev/null @@ -1 +0,0 @@ -22 diff --git a/miniProgram/babel.config.js b/miniProgram/babel.config.js index beb1871..72bd1a1 100644 --- a/miniProgram/babel.config.js +++ b/miniProgram/babel.config.js @@ -1,9 +1,11 @@ +// babel-preset-taro 更多选项和默认值: +// https://docs.taro.zone/docs/next/babel-config module.exports = { presets: [ ['taro', { framework: 'react', ts: true, compiler: 'webpack5', - }], - ], + }] + ] } diff --git a/miniProgram/config/dev.ts b/miniProgram/config/dev.ts index 8d8716e..aa5a594 100644 --- a/miniProgram/config/dev.ts +++ b/miniProgram/config/dev.ts @@ -1,8 +1,10 @@ -import type { UserConfigExport } from '@tarojs/cli' +import type { UserConfigExport } from "@tarojs/cli" export default { - env: { NODE_ENV: '"development"' }, - defineConstants: {}, + logger: { + quiet: false, + stats: true + }, mini: {}, - h5: {}, + h5: {} } satisfies UserConfigExport<'webpack5'> diff --git a/miniProgram/config/index.ts b/miniProgram/config/index.ts index acd86fc..25bf56c 100644 --- a/miniProgram/config/index.ts +++ b/miniProgram/config/index.ts @@ -1,38 +1,58 @@ -import { defineConfig } from '@tarojs/cli' -import type { UserConfigExport } from '@tarojs/cli' - +import { defineConfig, type UserConfigExport } from '@tarojs/cli' +import path from 'node:path' +import TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin' import devConfig from './dev' import prodConfig from './prod' +const assetPerformanceBudget = 384 * 1024 +const entrypointPerformanceBudget = 640 * 1024 + export default defineConfig<'webpack5'>(async (merge) => { const baseConfig: UserConfigExport<'webpack5'> = { - projectName: 'BITerStore', - date: '2026-08-26', - designWidth: 390, - deviceRatio: { 390: 2 }, - sourceRoot: 'src', - outputRoot: 'dist', + projectName: 'BITerStore', date: '2026-08-26', designWidth: 390, + deviceRatio: { 390: 1, 750: 2 }, sourceRoot: 'src', outputRoot: 'dist', framework: 'react', - compiler: 'webpack5', + compiler: { type: 'webpack5', prebundle: { exclude: ['lucide-react'] } }, cache: { enable: true }, + defineConstants: { __BITERSTORE_E2E__: JSON.stringify(process.env.BITERSTORE_E2E === '1') }, + copy: { patterns: [{ from: 'src/assets', to: 'dist/assets' }, { from: 'src/hosting/_redirects', to: 'dist' }], options: {} }, mini: { - postcss: { - pxtransform: { enable: true, config: {} }, - cssModules: { enable: false, config: { namingPattern: 'module', generateScopedName: '[name]__[local]___[hash:base64:5]' } }, - }, + postcss: { pxtransform: { enable: true, config: {} }, cssModules: { enable: false } }, + webpackChain(chain) { + chain.performance + .maxAssetSize(assetPerformanceBudget) + .maxEntrypointSize(entrypointPerformanceBudget) + chain.resolve.plugin('tsconfig-paths').use(TsconfigPathsPlugin) + } }, h5: { - publicPath: '/', - staticDirectory: 'static', - router: { mode: 'browser' }, - postcss: { - autoprefixer: { enable: true, config: {} }, - cssModules: { enable: false, config: { namingPattern: 'module', generateScopedName: '[name]__[local]___[hash:base64:5]' } }, + publicPath: '/', staticDirectory: 'static', + router: { + mode: 'browser', + customRoutes: { + '/pages/welcome/index': '/welcome', '/pages/onboarding/index': '/onboarding', + '/pages/home/index': '/home', '/pages/search/index': ['/search', '/category'], + '/pages/listing/detail': '/books', '/pages/publish/index': '/publish', + '/pages/messages/index': '/messages', '/pages/notification/detail': '/notifications', '/pages/chat/index': '/chat', + '/pages/profile/index': '/profile', '/pages/favorites/index': '/favorites', + '/pages/my-listings/index': '/my-listings', '/pages/states/index': '/states' + } }, - }, + miniCssExtractPluginOption: { ignoreOrder: true }, + postcss: { htmltransform: { enable: false }, pxtransform: { enable: false, config: {} }, autoprefixer: { enable: true, config: {} }, cssModules: { enable: false } }, + webpackChain(chain) { + chain.performance + .maxAssetSize(assetPerformanceBudget) + .maxEntrypointSize(entrypointPerformanceBudget) + chain.resolve.plugin('tsconfig-paths').use(TsconfigPathsPlugin) + chain.module.rule('script').include.add(path.resolve(__dirname, '../../web/app')) + chain.resolve.alias + .set('next/image', path.resolve(__dirname, '../src/h5/next-image.tsx')) + .set('lucide-react$', path.resolve(__dirname, '../src/h5/lucide-react.ts')) + .set('react', path.resolve(__dirname, '../node_modules/react')) + .set('react-dom', path.resolve(__dirname, '../node_modules/react-dom')) + } + } } - - return process.env.NODE_ENV === 'development' - ? merge({}, baseConfig, devConfig) - : merge({}, baseConfig, prodConfig) + return merge({}, baseConfig, process.env.NODE_ENV === 'development' ? devConfig : prodConfig) }) diff --git a/miniProgram/config/prod.ts b/miniProgram/config/prod.ts index 8554a16..8696957 100644 --- a/miniProgram/config/prod.ts +++ b/miniProgram/config/prod.ts @@ -1,8 +1,33 @@ -import type { UserConfigExport } from '@tarojs/cli' +import type { UserConfigExport } from "@tarojs/cli" export default { - env: { NODE_ENV: '"production"' }, - defineConstants: {}, mini: {}, - h5: {}, + h5: { + /** + * WebpackChain 插件配置 + * @docs https://github.com/neutrinojs/webpack-chain + */ + // webpackChain (chain) { + // /** + // * 如果 h5 端编译后体积过大,可以使用 webpack-bundle-analyzer 插件对打包体积进行分析。 + // * @docs https://github.com/webpack-contrib/webpack-bundle-analyzer + // */ + // chain.plugin('analyzer') + // .use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin, []) + // /** + // * 如果 h5 端首屏加载时间过长,可以使用 prerender-spa-plugin 插件预加载首页。 + // * @docs https://github.com/chrisvfritz/prerender-spa-plugin + // */ + // const path = require('path') + // const Prerender = require('prerender-spa-plugin') + // const staticDir = path.join(__dirname, '..', 'dist') + // chain + // .plugin('prerender') + // .use(new Prerender({ + // staticDir, + // routes: [ '/pages/index/index' ], + // postProcess: (context) => ({ ...context, outputPath: path.join(staticDir, 'index.html') }) + // })) + // } + } } satisfies UserConfigExport<'webpack5'> diff --git a/miniProgram/package-lock.json b/miniProgram/package-lock.json index 4dc962c..6b64e60 100644 --- a/miniProgram/package-lock.json +++ b/miniProgram/package-lock.json @@ -1,14 +1,16 @@ { - "name": "biterstore-taro-client", - "version": "0.2.0", + "name": "@biterstore/taro-client", + "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "biterstore-taro-client", - "version": "0.2.0", + "name": "@biterstore/taro-client", + "version": "0.1.0", "dependencies": { + "@babel/runtime": "7.28.4", "@tarojs/components": "4.2.1", + "@tarojs/helper": "4.2.1", "@tarojs/plugin-framework-react": "4.2.1", "@tarojs/plugin-platform-h5": "4.2.1", "@tarojs/plugin-platform-weapp": "4.2.1", @@ -16,29 +18,36 @@ "@tarojs/runtime": "4.2.1", "@tarojs/shared": "4.2.1", "@tarojs/taro": "4.2.1", + "lucide-react": "1.34.0", "react": "18.3.1", "react-dom": "18.3.1" }, "devDependencies": { "@babel/core": "7.29.7", - "@babel/preset-react": "7.28.5", + "@babel/plugin-transform-class-properties": "7.25.9", + "@babel/preset-react": "7.27.1", + "@pmmmwh/react-refresh-webpack-plugin": "0.5.17", "@tarojs/cli": "4.2.1", + "@tarojs/taro-loader": "4.2.1", "@tarojs/webpack5-runner": "4.2.1", - "@types/node": "22.19.19", + "@types/node": "22.18.6", "@types/react": "18.3.24", - "@types/react-dom": "18.3.7", + "@types/webpack-env": "1.18.8", "babel-preset-taro": "4.2.1", "dotenv": "17.4.2", + "eslint": "8.57.1", + "eslint-config-taro": "4.2.1", + "eslint-plugin-react": "7.34.1", + "eslint-plugin-react-hooks": "4.4.0", "miniprogram-automator": "0.12.1", - "miniprogram-automator-mcp": "0.1.1", "react-refresh": "0.14.2", - "sass": "1.77.8", + "tsconfig-paths-webpack-plugin": "4.2.0", "typescript": "5.4.5", - "vite": "4.5.14", - "vitest": "0.34.6" + "vitest": "0.34.6", + "webpack": "5.91.0" }, "engines": { - "node": ">=22.13.0 <25" + "node": "22.13.x" } }, "node_modules/@adobe/css-tools": { @@ -46,7 +55,8 @@ "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.3.tgz", "integrity": "sha512-rE0Pygv0sEZ4vBWHlAgJLGDU7Pm8xoO6p3wsEceb7GYAjScrOHpEo8KK/eVkAcnSM+slAEtXjA2JpdjLp4fJQQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@asamuzakjp/css-color": { "version": "3.2.0", @@ -97,7 +107,6 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.7", @@ -123,6 +132,35 @@ "url": "https://opencollective.com/babel" } }, + "node_modules/@babel/eslint-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.29.7.tgz", + "integrity": "sha512-zxt+UJTOMKvUt3yOg+D58MLuz334pHp93qifMFcjIIO+9hN6t+ufw2gi7vDPMpxvfnHRR+3VVXvIjineCcgyXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", + "eslint-visitor-keys": "^2.1.0", + "semver": "^6.3.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || >=14.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0", + "eslint": "^7.5.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/@babel/eslint-parser/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10" + } + }, "node_modules/@babel/generator": { "version": "7.29.8", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", @@ -735,14 +773,14 @@ } }, "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.29.7.tgz", - "integrity": "sha512-GtcpjFvanPfzNQi3eTitsCqtRRmmqzpy/A+yhTR1HaZo1Ly3EA8ZXxlPyHdR8/IuRMYc3E4wdGBewB2QKQjAaA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.9.tgz", + "integrity": "sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1702,6 +1740,23 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-class-properties": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.29.7.tgz", + "integrity": "sha512-GtcpjFvanPfzNQi3eTitsCqtRRmmqzpy/A+yhTR1HaZo1Ly3EA8ZXxlPyHdR8/IuRMYc3E4wdGBewB2QKQjAaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/preset-env/node_modules/babel-plugin-polyfill-corejs3": { "version": "0.14.2", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.2.tgz", @@ -1732,16 +1787,15 @@ } }, "node_modules/@babel/preset-react": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.28.5.tgz", - "integrity": "sha512-Z3J8vhRq7CeLjdC58jLv4lnZ5RKFUJWqH5emvxmv9Hv3BD1T9R/Im713R4MTKwvFaV74ejZ3sM01LyEKk4ugNQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.27.1.tgz", + "integrity": "sha512-oJHWh2gLhU9dW9HHr42q0cI0/iHHXTLGe39qvpAZZzagHy0MzYLCnCVV0symeRvzmjHyVU7mw2K06E6u/JwbhA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", - "@babel/plugin-transform-react-display-name": "^7.28.0", + "@babel/plugin-transform-react-display-name": "^7.27.1", "@babel/plugin-transform-react-jsx": "^7.27.1", "@babel/plugin-transform-react-jsx-development": "^7.27.1", "@babel/plugin-transform-react-pure-annotations": "^7.27.1" @@ -1774,11 +1828,10 @@ } }, "node_modules/@babel/runtime": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", - "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=6.9.0" } @@ -1929,7 +1982,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -1953,7 +2005,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" } @@ -2431,9 +2482,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.41.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.41.0.tgz", - "integrity": "sha512-LxcyMGxwmTh2lY9FwHPGWOHmYFCZvbrFCBZL4FzSSsxsRPuhrYUg/49/0KDfW8tnIEaEHtfmn6+NPN+1DqaNmA==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", "dev": true, "license": "MIT", "engines": { @@ -2455,28 +2506,15 @@ "@hapi/hoek": "^9.0.0" } }, - "node_modules/@hono/node-server": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-2.1.1.tgz", - "integrity": "sha512-ELuehkj5VCBdgEw9zs+ivkKwyzzUCSQuE96YmiPvn1ECBoZCczbFXJLeEGMTYjphP6gydh4pHMqEYPVMYUVgQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - }, - "peerDependencies": { - "hono": "^4" - } - }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", "deprecated": "Use @eslint/config-array instead", "dev": true, "license": "Apache-2.0", "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", + "@humanwhocodes/object-schema": "^2.0.3", "debug": "^4.3.1", "minimatch": "^3.0.5" }, @@ -2677,6 +2715,15 @@ "@jimp/custom": ">=0.3.5" } }, + "node_modules/@jimp/bmp/node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true, + "license": "MIT" + }, "node_modules/@jimp/core": { "version": "0.6.8", "resolved": "https://registry.npmjs.org/@jimp/core/-/core-0.6.8.tgz", @@ -2697,6 +2744,15 @@ "tinycolor2": "^1.4.1" } }, + "node_modules/@jimp/core/node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true, + "license": "MIT" + }, "node_modules/@jimp/core/node_modules/file-type": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/file-type/-/file-type-9.0.0.tgz", @@ -2713,12 +2769,20 @@ "integrity": "sha512-FrYlzZRVXP2vuVwd7Nc2dlK+iZk4g6IaT1Ib8Z6vU5Kkwlt83FJIPJ2UUFABf3bF5big0wkk8ZUihWxE4Nzdng==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jimp/core": "^0.6.8", "core-js": "^2.5.7" } }, + "node_modules/@jimp/custom/node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true, + "license": "MIT" + }, "node_modules/@jimp/gif": { "version": "0.6.8", "resolved": "https://registry.npmjs.org/@jimp/gif/-/gif-0.6.8.tgz", @@ -2734,6 +2798,15 @@ "@jimp/custom": ">=0.3.5" } }, + "node_modules/@jimp/gif/node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true, + "license": "MIT" + }, "node_modules/@jimp/jpeg": { "version": "0.6.8", "resolved": "https://registry.npmjs.org/@jimp/jpeg/-/jpeg-0.6.8.tgz", @@ -2749,13 +2822,21 @@ "@jimp/custom": ">=0.3.5" } }, + "node_modules/@jimp/jpeg/node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true, + "license": "MIT" + }, "node_modules/@jimp/plugin-blit": { "version": "0.6.8", "resolved": "https://registry.npmjs.org/@jimp/plugin-blit/-/plugin-blit-0.6.8.tgz", "integrity": "sha512-7Tl6YpKTSpvwQbnGNhsfX2zyl3jRVVopd276Y2hF2zpDz9Bycow7NdfNU/4Nx1jaf96X6uWOtSVINcQ7rGd47w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jimp/utils": "^0.6.8", "core-js": "^2.5.7" @@ -2764,6 +2845,15 @@ "@jimp/custom": ">=0.3.5" } }, + "node_modules/@jimp/plugin-blit/node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true, + "license": "MIT" + }, "node_modules/@jimp/plugin-blur": { "version": "0.6.8", "resolved": "https://registry.npmjs.org/@jimp/plugin-blur/-/plugin-blur-0.6.8.tgz", @@ -2778,6 +2868,15 @@ "@jimp/custom": ">=0.3.5" } }, + "node_modules/@jimp/plugin-blur/node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true, + "license": "MIT" + }, "node_modules/@jimp/plugin-color": { "version": "0.6.8", "resolved": "https://registry.npmjs.org/@jimp/plugin-color/-/plugin-color-0.6.8.tgz", @@ -2793,6 +2892,15 @@ "@jimp/custom": ">=0.3.5" } }, + "node_modules/@jimp/plugin-color/node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true, + "license": "MIT" + }, "node_modules/@jimp/plugin-contain": { "version": "0.6.8", "resolved": "https://registry.npmjs.org/@jimp/plugin-contain/-/plugin-contain-0.6.8.tgz", @@ -2810,6 +2918,15 @@ "@jimp/plugin-scale": ">=0.3.5" } }, + "node_modules/@jimp/plugin-contain/node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true, + "license": "MIT" + }, "node_modules/@jimp/plugin-cover": { "version": "0.6.8", "resolved": "https://registry.npmjs.org/@jimp/plugin-cover/-/plugin-cover-0.6.8.tgz", @@ -2827,13 +2944,21 @@ "@jimp/plugin-scale": ">=0.3.5" } }, + "node_modules/@jimp/plugin-cover/node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true, + "license": "MIT" + }, "node_modules/@jimp/plugin-crop": { "version": "0.6.8", "resolved": "https://registry.npmjs.org/@jimp/plugin-crop/-/plugin-crop-0.6.8.tgz", "integrity": "sha512-CbrcpWE2xxPK1n/JoTXzhRUhP4mO07mTWaSavenCg664oQl/9XCtL+A0FekuNHzIvn4myEqvkiTwN7FsbunS/Q==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jimp/utils": "^0.6.8", "core-js": "^2.5.7" @@ -2842,6 +2967,15 @@ "@jimp/custom": ">=0.3.5" } }, + "node_modules/@jimp/plugin-crop/node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true, + "license": "MIT" + }, "node_modules/@jimp/plugin-displace": { "version": "0.6.8", "resolved": "https://registry.npmjs.org/@jimp/plugin-displace/-/plugin-displace-0.6.8.tgz", @@ -2856,6 +2990,15 @@ "@jimp/custom": ">=0.3.5" } }, + "node_modules/@jimp/plugin-displace/node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true, + "license": "MIT" + }, "node_modules/@jimp/plugin-dither": { "version": "0.6.8", "resolved": "https://registry.npmjs.org/@jimp/plugin-dither/-/plugin-dither-0.6.8.tgz", @@ -2870,6 +3013,15 @@ "@jimp/custom": ">=0.3.5" } }, + "node_modules/@jimp/plugin-dither/node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true, + "license": "MIT" + }, "node_modules/@jimp/plugin-flip": { "version": "0.6.8", "resolved": "https://registry.npmjs.org/@jimp/plugin-flip/-/plugin-flip-0.6.8.tgz", @@ -2885,6 +3037,15 @@ "@jimp/plugin-rotate": ">=0.3.5" } }, + "node_modules/@jimp/plugin-flip/node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true, + "license": "MIT" + }, "node_modules/@jimp/plugin-gaussian": { "version": "0.6.8", "resolved": "https://registry.npmjs.org/@jimp/plugin-gaussian/-/plugin-gaussian-0.6.8.tgz", @@ -2899,6 +3060,15 @@ "@jimp/custom": ">=0.3.5" } }, + "node_modules/@jimp/plugin-gaussian/node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true, + "license": "MIT" + }, "node_modules/@jimp/plugin-invert": { "version": "0.6.8", "resolved": "https://registry.npmjs.org/@jimp/plugin-invert/-/plugin-invert-0.6.8.tgz", @@ -2913,6 +3083,15 @@ "@jimp/custom": ">=0.3.5" } }, + "node_modules/@jimp/plugin-invert/node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true, + "license": "MIT" + }, "node_modules/@jimp/plugin-mask": { "version": "0.6.8", "resolved": "https://registry.npmjs.org/@jimp/plugin-mask/-/plugin-mask-0.6.8.tgz", @@ -2927,6 +3106,15 @@ "@jimp/custom": ">=0.3.5" } }, + "node_modules/@jimp/plugin-mask/node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true, + "license": "MIT" + }, "node_modules/@jimp/plugin-normalize": { "version": "0.6.8", "resolved": "https://registry.npmjs.org/@jimp/plugin-normalize/-/plugin-normalize-0.6.8.tgz", @@ -2941,6 +3129,15 @@ "@jimp/custom": ">=0.3.5" } }, + "node_modules/@jimp/plugin-normalize/node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true, + "license": "MIT" + }, "node_modules/@jimp/plugin-print": { "version": "0.6.8", "resolved": "https://registry.npmjs.org/@jimp/plugin-print/-/plugin-print-0.6.8.tgz", @@ -2957,13 +3154,21 @@ "@jimp/plugin-blit": ">=0.3.5" } }, + "node_modules/@jimp/plugin-print/node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true, + "license": "MIT" + }, "node_modules/@jimp/plugin-resize": { "version": "0.6.8", "resolved": "https://registry.npmjs.org/@jimp/plugin-resize/-/plugin-resize-0.6.8.tgz", "integrity": "sha512-27nPh8L1YWsxtfmV/+Ub5dOTpXyC0HMF2cu52RQSCYxr+Lm1+23dJF70AF1poUbUe+FWXphwuUxQzjBJza9UoA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jimp/utils": "^0.6.8", "core-js": "^2.5.7" @@ -2972,13 +3177,21 @@ "@jimp/custom": ">=0.3.5" } }, + "node_modules/@jimp/plugin-resize/node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true, + "license": "MIT" + }, "node_modules/@jimp/plugin-rotate": { "version": "0.6.8", "resolved": "https://registry.npmjs.org/@jimp/plugin-rotate/-/plugin-rotate-0.6.8.tgz", "integrity": "sha512-GbjETvL05BDoLdszNUV4Y0yLkHf177MnqGqilA113LIvx9aD0FtUopGXYfRGVvmtTOTouoaGJUc+K6qngvKxww==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jimp/utils": "^0.6.8", "core-js": "^2.5.7" @@ -2990,13 +3203,21 @@ "@jimp/plugin-resize": ">=0.3.5" } }, + "node_modules/@jimp/plugin-rotate/node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true, + "license": "MIT" + }, "node_modules/@jimp/plugin-scale": { "version": "0.6.8", "resolved": "https://registry.npmjs.org/@jimp/plugin-scale/-/plugin-scale-0.6.8.tgz", "integrity": "sha512-GzIYWR/oCUK2jAwku23zt19V1ssaEU4pL0x2XsLNKuuJEU6DvEytJyTMXCE7OLG/MpDBQcQclJKHgiyQm5gIOQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jimp/utils": "^0.6.8", "core-js": "^2.5.7" @@ -3006,6 +3227,15 @@ "@jimp/plugin-resize": ">=0.3.5" } }, + "node_modules/@jimp/plugin-scale/node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true, + "license": "MIT" + }, "node_modules/@jimp/plugins": { "version": "0.6.8", "resolved": "https://registry.npmjs.org/@jimp/plugins/-/plugins-0.6.8.tgz", @@ -3037,11 +3267,20 @@ "@jimp/custom": ">=0.3.5" } }, - "node_modules/@jimp/png": { - "version": "0.6.8", - "resolved": "https://registry.npmjs.org/@jimp/png/-/png-0.6.8.tgz", - "integrity": "sha512-JHHg/BZ7KDtHQrcG+a7fztw45rdf7okL/YwkN4qU5FH7Fcrp41nX5QnRviDtD9hN+GaNC7kvjvcqRAxW25qjew==", - "dev": true, + "node_modules/@jimp/plugins/node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true, + "license": "MIT" + }, + "node_modules/@jimp/png": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@jimp/png/-/png-0.6.8.tgz", + "integrity": "sha512-JHHg/BZ7KDtHQrcG+a7fztw45rdf7okL/YwkN4qU5FH7Fcrp41nX5QnRviDtD9hN+GaNC7kvjvcqRAxW25qjew==", + "dev": true, "license": "MIT", "dependencies": { "@jimp/utils": "^0.6.8", @@ -3052,6 +3291,15 @@ "@jimp/custom": ">=0.3.5" } }, + "node_modules/@jimp/png/node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true, + "license": "MIT" + }, "node_modules/@jimp/tiff": { "version": "0.6.8", "resolved": "https://registry.npmjs.org/@jimp/tiff/-/tiff-0.6.8.tgz", @@ -3066,6 +3314,15 @@ "@jimp/custom": ">=0.3.5" } }, + "node_modules/@jimp/tiff/node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true, + "license": "MIT" + }, "node_modules/@jimp/types": { "version": "0.6.8", "resolved": "https://registry.npmjs.org/@jimp/types/-/types-0.6.8.tgz", @@ -3085,6 +3342,15 @@ "@jimp/custom": ">=0.3.5" } }, + "node_modules/@jimp/types/node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true, + "license": "MIT" + }, "node_modules/@jimp/utils": { "version": "0.6.8", "resolved": "https://registry.npmjs.org/@jimp/utils/-/utils-0.6.8.tgz", @@ -3095,6 +3361,15 @@ "core-js": "^2.5.7" } }, + "node_modules/@jimp/utils/node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true, + "license": "MIT" + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", @@ -3158,77 +3433,46 @@ "devOptional": true, "license": "MIT" }, - "node_modules/@modelcontextprotocol/sdk": { - "version": "1.30.0", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.30.0.tgz", - "integrity": "sha512-xKd8OIzlqNzcqcNumGAa6g+PW2kjD5vrpcKOnfldAUPP3j7lnqMPwlTXQm8gF+UwH72z0lqaRbjr9hqGz0eITA==", + "node_modules/@napi-rs/triples": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@napi-rs/triples/-/triples-1.2.0.tgz", + "integrity": "sha512-HAPjR3bnCsdXBsATpDIP5WCrw0JcACwhhrwIAQhiR46n+jm+a2F8kBsfseAuWtSyQ+H3Yebt2k43B5dy+04yMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", "dev": true, "license": "MIT", "dependencies": { - "@hono/node-server": "^1.19.9 || ^2.0.5", - "ajv": "^8.17.1", - "ajv-formats": "^3.0.1", - "content-type": "^1.0.5", - "cors": "^2.8.5", - "cross-spawn": "^7.0.5", - "eventsource": "^3.0.2", - "eventsource-parser": "^3.0.0", - "express": "^5.2.1", - "express-rate-limit": "^8.2.1", - "hono": "^4.11.4", - "jose": "^6.1.3", - "json-schema-typed": "^8.0.2", - "pkce-challenge": "^5.0.0", - "raw-body": "^3.0.0", - "zod": "^3.25 || ^4.0", - "zod-to-json-schema": "^3.25.1" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@cfworker/json-schema": "^4.1.1", - "zod": "^3.25 || ^4.0" - }, - "peerDependenciesMeta": { - "@cfworker/json-schema": { - "optional": true - }, - "zod": { - "optional": false - } + "eslint-scope": "5.1.1" } }, - "node_modules/@modelcontextprotocol/sdk/node_modules/ajv": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", - "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "engines": { + "node": ">=8.0.0" } }, - "node_modules/@modelcontextprotocol/sdk/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, - "node_modules/@napi-rs/triples": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@napi-rs/triples/-/triples-1.2.0.tgz", - "integrity": "sha512-HAPjR3bnCsdXBsATpDIP5WCrw0JcACwhhrwIAQhiR46n+jm+a2F8kBsfseAuWtSyQ+H3Yebt2k43B5dy+04yMA==", + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, - "license": "MIT" + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", @@ -3268,465 +3512,877 @@ "node": ">= 8" } }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, + "node_modules/@parcel/watcher": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.6.0.tgz", + "integrity": "sha512-7FNeNl8NCE7aINx7WXiKQrPYZWC/hvrTsmk6zmxbI7LTXE7hVek/n8AfVgpe2y82zl3w0HvCHN0bVKMBoJcC0w==", + "hasInstallScript": true, "license": "MIT", "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@rnx-kit/babel-preset-metro-react-native": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/@rnx-kit/babel-preset-metro-react-native/-/babel-preset-metro-react-native-1.1.8.tgz", - "integrity": "sha512-8DotuBK1ZgV0H/tmCmtW/3ofA7JR/8aPqSu9lKnuqwBfq4bxz+w1sMyfFl89m4teWlkhgyczWBGD6NCLqTgi9A==", - "dev": true, - "license": "MIT", "dependencies": { - "@rnx-kit/console": "^1.1.0", - "babel-plugin-const-enum": "^1.0.0" + "detect-libc": "^2.0.3", + "is-glob": "^4.0.3", + "node-addon-api": "^7.0.0", + "picomatch": "^4.0.4" }, - "peerDependencies": { - "@babel/core": "^7.20.0", - "@babel/plugin-transform-typescript": "^7.20.0", - "@babel/runtime": "^7.20.0", - "@react-native/babel-preset": "*", - "metro-react-native-babel-preset": "*" + "engines": { + "node": ">= 10.0.0" }, - "peerDependenciesMeta": { - "@babel/plugin-transform-typescript": { - "optional": true - }, - "@react-native/babel-preset": { - "optional": true - }, - "metro-react-native-babel-preset": { - "optional": true - } - } - }, - "node_modules/@rnx-kit/console": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rnx-kit/console/-/console-1.1.0.tgz", - "integrity": "sha512-N+zFhTSXroiK4eL26vs61Pmtl7wzTPAKLd4JKw9/fk5cNAHUscCXF/uclzuYN61Ye5AwygIvcwbm9wv4Jfa92A==", - "dev": true, - "license": "MIT" - }, - "node_modules/@sideway/address": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", - "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/hoek": "^9.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.6.0", + "@parcel/watcher-darwin-arm64": "2.6.0", + "@parcel/watcher-darwin-x64": "2.6.0", + "@parcel/watcher-freebsd-x64": "2.6.0", + "@parcel/watcher-linux-arm-glibc": "2.6.0", + "@parcel/watcher-linux-arm-musl": "2.6.0", + "@parcel/watcher-linux-arm64-glibc": "2.6.0", + "@parcel/watcher-linux-arm64-musl": "2.6.0", + "@parcel/watcher-linux-x64-glibc": "2.6.0", + "@parcel/watcher-linux-x64-musl": "2.6.0", + "@parcel/watcher-win32-arm64": "2.6.0", + "@parcel/watcher-win32-x64": "2.6.0" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.6.0.tgz", + "integrity": "sha512-trgpLSCKRC/huFjXX/Smh+0sWe4+YtKfktIToiMl59ghz7z+qkH6kMvNnUbLyRs9N11t8l4svSCs1+5B3rOAhA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@sideway/formula": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", - "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", - "license": "BSD-3-Clause" - }, - "node_modules/@sideway/pinpoint": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", - "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", - "license": "BSD-3-Clause" - }, - "node_modules/@sinclair/typebox": { - "version": "0.27.12", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.12.tgz", - "integrity": "sha512-hhyNJ+nbR6ZR7pToHvllEFun9TL0sbL+tk/ON75lo+Xas054uez98qRbsuNt7MBCyZKK4+8Yli/OAGZhmfBZ/g==", - "dev": true, - "license": "MIT" - }, - "node_modules/@sindresorhus/is": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz", - "integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==", - "dev": true, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.6.0.tgz", + "integrity": "sha512-Y3QV0gl7Q1zbfueunkWIERICbEojQFCgpyG7YqOGNFLsckXyI1xu9mAIUpKY9QBYzBtSkN8dBPwd3yiAO9ovMw==", + "cpu": [ + "arm64" + ], "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=4" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@sindresorhus/merge-streams": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", - "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", - "dev": true, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.6.0.tgz", + "integrity": "sha512-Ohv6OpzhUfKYD7Beb8kDvG0jbIxORCYY1JRdZnaBtnjjkJxgD7ZVL0nw2sCYd0yTMKTvz3nnTnOF3cDifK+kvw==", + "cpu": [ + "x64" + ], "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=18" + "node": ">= 10.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@stencil/core": { - "version": "2.22.3", - "resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.22.3.tgz", - "integrity": "sha512-kmVA0M/HojwsfkeHsifvHVIYe4l5tin7J5+DLgtl8h6WWfiMClND5K3ifCXXI2ETDNKiEk21p6jql3Fx9o2rng==", + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.6.0.tgz", + "integrity": "sha512-5HmXvDgs8VK+74jF9y9/2FE3/OnlcKmc56tjmSrEuZjpSZOGL+fvAu+HKJBdPs9uwoP2hE6TlSUpXZ/C5jUFmQ==", + "cpu": [ + "x64" + ], "license": "MIT", - "bin": { - "stencil": "bin/stencil" - }, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=12.10.0", - "npm": ">=6.0.0" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@swc/core": { - "version": "1.3.96", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.96.tgz", - "integrity": "sha512-zwE3TLgoZwJfQygdv2SdCK9mRLYluwDOM53I+dT6Z5ZvrgVENmY3txvWDvduzkV+/8IuvrRbVezMpxcojadRdQ==", - "hasInstallScript": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@swc/counter": "^0.1.1", - "@swc/types": "^0.1.5" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/swc" - }, - "optionalDependencies": { - "@swc/core-darwin-arm64": "1.3.96", - "@swc/core-darwin-x64": "1.3.96", - "@swc/core-linux-arm-gnueabihf": "1.3.96", - "@swc/core-linux-arm64-gnu": "1.3.96", - "@swc/core-linux-arm64-musl": "1.3.96", - "@swc/core-linux-x64-gnu": "1.3.96", - "@swc/core-linux-x64-musl": "1.3.96", - "@swc/core-win32-arm64-msvc": "1.3.96", - "@swc/core-win32-ia32-msvc": "1.3.96", - "@swc/core-win32-x64-msvc": "1.3.96" - }, - "peerDependencies": { - "@swc/helpers": "^0.5.0" - }, - "peerDependenciesMeta": { - "@swc/helpers": { - "optional": true - } - } - }, - "node_modules/@swc/core-darwin-arm64": { - "version": "1.3.96", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.96.tgz", - "integrity": "sha512-8hzgXYVd85hfPh6mJ9yrG26rhgzCmcLO0h1TIl8U31hwmTbfZLzRitFQ/kqMJNbIBCwmNH1RU2QcJnL3d7f69A==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-darwin-x64": { - "version": "1.3.96", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.96.tgz", - "integrity": "sha512-mFp9GFfuPg+43vlAdQZl0WZpZSE8sEzqL7sr/7Reul5McUHP0BaLsEzwjvD035ESfkY8GBZdLpMinblIbFNljQ==", + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.6.0.tgz", + "integrity": "sha512-Ps/hui3A+vMbjdqlqAowK2ZL8+BO8dBjxeWXj6npTBs3jx4wWmbPpaLuqwrQrSqIVMCnpWo238bJ1U37GhQOYg==", "cpu": [ - "x64" + "arm" ], - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, "os": [ - "darwin" + "linux" ], "engines": { - "node": ">=10" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.3.96", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.96.tgz", - "integrity": "sha512-8UEKkYJP4c8YzYIY/LlbSo8z5Obj4hqcv/fUTHiEePiGsOddgGf7AWjh56u7IoN/0uEmEro59nc1ChFXqXSGyg==", + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.6.0.tgz", + "integrity": "sha512-9c6AUHgHoG+IY88MRIHupztQiQnrbqHYQjkM2btA+Bf/wQnQMuiD0Wfk1EVv3TlNT3x41uU71rn6E4xh/+zvkw==", "cpu": [ "arm" ], - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=10" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.3.96", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.96.tgz", - "integrity": "sha512-c/IiJ0s1y3Ymm2BTpyC/xr6gOvoqAVETrivVXHq68xgNms95luSpbYQ28rqaZC8bQC8M5zdXpSc0T8DJu8RJGw==", + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.6.0.tgz", + "integrity": "sha512-yHRqS2owEXe6Hic9z6Mh1ECsCd+ODVOGvZDyciqRd21+v+o+DnXMOrw50DSpIG2sb8GPEaPPmfeCAWKPJdq46g==", "cpu": [ "arm64" ], - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=10" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.3.96", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.96.tgz", - "integrity": "sha512-i5/UTUwmJLri7zhtF6SAo/4QDQJDH2fhYJaBIUhrICmIkRO/ltURmpejqxsM/ye9Jqv5zG7VszMC0v/GYn/7BQ==", + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.6.0.tgz", + "integrity": "sha512-WhB2e/V7rqdHHWZusBSPuy5Ei8S6lSz6FE5TKKQz5h3a0O+C+mhY7vxU9b/stqvMb8beLnPY82ZrFTLKs+SrKA==", "cpu": [ "arm64" ], - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=10" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.3.96", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.96.tgz", - "integrity": "sha512-USdaZu8lTIkm4Yf9cogct/j5eqtdZqTgcTib4I+NloUW0E/hySou3eSyp3V2UAA1qyuC72ld1otXuyKBna0YKQ==", + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.6.0.tgz", + "integrity": "sha512-ulGE6x6Oz6iAwg75T8YQSoguBWasniIbX+QWpaYPcCnDOpdWX3k+4xbEYPZVLxOuoJI+svJJPD3sEj8G7lrQ3A==", "cpu": [ "x64" ], - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=10" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@swc/core-linux-x64-musl": { - "version": "1.3.96", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.96.tgz", - "integrity": "sha512-QYErutd+G2SNaCinUVobfL7jWWjGTI0QEoQ6hqTp7PxCJS/dmKmj3C5ZkvxRYcq7XcZt7ovrYCTwPTHzt6lZBg==", + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.6.0.tgz", + "integrity": "sha512-tkBYKt7YQrjIJWYDnto2YgO8MRkjlMTSNoRHzsXinBqbLdeOM3L32wPZJvIZxqaLMfSlS/4sUjH/6STVP/XDLw==", "cpu": [ "x64" ], - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=10" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.3.96", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.96.tgz", - "integrity": "sha512-hjGvvAduA3Un2cZ9iNP4xvTXOO4jL3G9iakhFsgVhpkU73SGmK7+LN8ZVBEu4oq2SUcHO6caWvnZ881cxGuSpg==", + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.6.0.tgz", + "integrity": "sha512-gIZAP23jaHjGWasY/TY6yL7NHFClf0Ga7FN+iINvk+KN94rhm94lYZhFsbYFNcA04/onvGD9kKmiJLJB2HbNwQ==", "cpu": [ "arm64" ], - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=10" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.3.96", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.96.tgz", - "integrity": "sha512-Far2hVFiwr+7VPCM2GxSmbh3ikTpM3pDombE+d69hkedvYHYZxtTF+2LTKl/sXtpbUnsoq7yV/32c9R/xaaWfw==", + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.6.0.tgz", + "integrity": "sha512-cA+/pXV2YkfxlIcXOQ5fSWqAzzPyD78/x5qbK/I0vUkrlYHA8TIz+MXjAbGouguKVSI4bOmkTSJ1/poVSsgt+A==", "cpu": [ - "ia32" + "x64" ], - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=10" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.3.96", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.96.tgz", - "integrity": "sha512-4VbSAniIu0ikLf5mBX81FsljnfqjoVGleEkCQv4+zRlyZtO3FHoDPkeLVoy6WRlj7tyrRcfUJ4mDdPkbfTO14g==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0 AND MIT", + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", "optional": true, - "os": [ - "win32" - ], "engines": { - "node": ">=10" + "node": ">=14" } }, - "node_modules/@swc/counter": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", - "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", - "license": "Apache-2.0" - }, - "node_modules/@swc/register": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/@swc/register/-/register-0.1.10.tgz", - "integrity": "sha512-6STwH/q4dc3pitXLVkV7sP0Hiy+zBsU2wOF1aXpXR95pnH3RYHKIsDC+gvesfyB7jxNT9OOZgcqOp9RPxVTx9A==", - "deprecated": "Use @swc-node/register instead", - "license": "(Apache-2.0 OR MIT)", + "node_modules/@pmmmwh/react-refresh-webpack-plugin": { + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.17.tgz", + "integrity": "sha512-tXDyE1/jzFsHXjhRZQ3hMl0IVhYe5qula43LDWIhVfjp9G/nT5OQY5AORVOrkEGAUltBJOfOWeETbmhm6kHhuQ==", + "devOptional": true, + "license": "MIT", "dependencies": { - "lodash.clonedeep": "^4.5.0", - "pirates": "^4.0.1", - "source-map-support": "^0.5.13" + "ansi-html": "^0.0.9", + "core-js-pure": "^3.23.3", + "error-stack-parser": "^2.0.6", + "html-entities": "^2.1.0", + "loader-utils": "^2.0.4", + "schema-utils": "^4.2.0", + "source-map": "^0.7.3" }, - "bin": { - "swc-node": "bin/swc-node" + "engines": { + "node": ">= 10.13" }, "peerDependencies": { - "@swc/core": "^1.0.46" + "@types/webpack": "4.x || 5.x", + "react-refresh": ">=0.10.0 <1.0.0", + "sockjs-client": "^1.4.0", + "type-fest": ">=0.17.0 <5.0.0", + "webpack": ">=4.43.0 <6.0.0", + "webpack-dev-server": "3.x || 4.x || 5.x", + "webpack-hot-middleware": "2.x", + "webpack-plugin-serve": "0.x || 1.x" + }, + "peerDependenciesMeta": { + "@types/webpack": { + "optional": true + }, + "sockjs-client": { + "optional": true + }, + "type-fest": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + }, + "webpack-hot-middleware": { + "optional": true + }, + "webpack-plugin-serve": { + "optional": true + } } }, - "node_modules/@swc/types": { - "version": "0.1.28", - "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.28.tgz", - "integrity": "sha512-V6Mnml8v09QALx6K0elJ7o9K/MkVDtW3t6L+7Ou/JcWtb3xwId2AH4FeOceySd2JaO87IMw4+6vSZxLm34LPbw==", - "license": "Apache-2.0", + "node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "devOptional": true, + "license": "MIT", "dependencies": { - "@swc/counter": "^0.1.3" + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", - "dev": true, + "node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "devOptional": true, "license": "MIT", "dependencies": { - "defer-to-connect": "^1.0.1" + "fast-deep-equal": "^3.1.3" }, - "engines": { - "node": ">=6" + "peerDependencies": { + "ajv": "^8.8.2" } }, - "node_modules/@tarojs/api": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tarojs/api/-/api-4.2.1.tgz", - "integrity": "sha512-GlgqH/mx0EC+tYrcUnqa7vsGSOaAzIJNxvDcUESO6FiKb1xLESGmgGbaiEkqw29Nx/3j3lEXjHrCHJUdGy3X2Q==", - "license": "MIT", + "node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, "engines": { - "node": ">= 18" + "node": ">=8.9.0" + } + }, + "node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/schema-utils": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "devOptional": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "node_modules/@rnx-kit/babel-preset-metro-react-native": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@rnx-kit/babel-preset-metro-react-native/-/babel-preset-metro-react-native-1.1.8.tgz", + "integrity": "sha512-8DotuBK1ZgV0H/tmCmtW/3ofA7JR/8aPqSu9lKnuqwBfq4bxz+w1sMyfFl89m4teWlkhgyczWBGD6NCLqTgi9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rnx-kit/console": "^1.1.0", + "babel-plugin-const-enum": "^1.0.0" }, "peerDependencies": { - "@tarojs/runtime": "4.2.1", - "@tarojs/shared": "4.2.1" + "@babel/core": "^7.20.0", + "@babel/plugin-transform-typescript": "^7.20.0", + "@babel/runtime": "^7.20.0", + "@react-native/babel-preset": "*", + "metro-react-native-babel-preset": "*" + }, + "peerDependenciesMeta": { + "@babel/plugin-transform-typescript": { + "optional": true + }, + "@react-native/babel-preset": { + "optional": true + }, + "metro-react-native-babel-preset": { + "optional": true + } } }, - "node_modules/@tarojs/binding": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tarojs/binding/-/binding-4.2.1.tgz", - "integrity": "sha512-Sg4+gj00Fn8rKiUIeoS18jQtJVvc9TzK4BzwAEOwUaTBISU/PYCoXm5Sjuz4mN9jaaRuyCgzJ0NTkxOAjdY7Mg==", + "node_modules/@rnx-kit/console": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rnx-kit/console/-/console-1.1.0.tgz", + "integrity": "sha512-N+zFhTSXroiK4eL26vs61Pmtl7wzTPAKLd4JKw9/fk5cNAHUscCXF/uclzuYN61Ye5AwygIvcwbm9wv4Jfa92A==", "dev": true, - "hasInstallScript": true, + "license": "MIT" + }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sideway/address": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", + "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", + "license": "BSD-3-Clause" + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.12", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.12.tgz", + "integrity": "sha512-hhyNJ+nbR6ZR7pToHvllEFun9TL0sbL+tk/ON75lo+Xas054uez98qRbsuNt7MBCyZKK4+8Yli/OAGZhmfBZ/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sindresorhus/is": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz", + "integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@stencil/core": { + "version": "2.22.3", + "resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.22.3.tgz", + "integrity": "sha512-kmVA0M/HojwsfkeHsifvHVIYe4l5tin7J5+DLgtl8h6WWfiMClND5K3ifCXXI2ETDNKiEk21p6jql3Fx9o2rng==", "license": "MIT", + "bin": { + "stencil": "bin/stencil" + }, + "engines": { + "node": ">=12.10.0", + "npm": ">=6.0.0" + } + }, + "node_modules/@swc/core": { + "version": "1.3.96", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.96.tgz", + "integrity": "sha512-zwE3TLgoZwJfQygdv2SdCK9mRLYluwDOM53I+dT6Z5ZvrgVENmY3txvWDvduzkV+/8IuvrRbVezMpxcojadRdQ==", + "hasInstallScript": true, + "license": "Apache-2.0", "dependencies": { - "@napi-rs/triples": "1.2.0" + "@swc/counter": "^0.1.1", + "@swc/types": "^0.1.5" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" }, "optionalDependencies": { - "@tarojs/binding-darwin-arm64": "4.2.1", - "@tarojs/binding-darwin-x64": "4.2.1", - "@tarojs/binding-linux-arm64-gnu": "4.2.1", - "@tarojs/binding-linux-x64-gnu": "4.2.1", - "@tarojs/binding-win32-x64-msvc": "4.2.1" + "@swc/core-darwin-arm64": "1.3.96", + "@swc/core-darwin-x64": "1.3.96", + "@swc/core-linux-arm-gnueabihf": "1.3.96", + "@swc/core-linux-arm64-gnu": "1.3.96", + "@swc/core-linux-arm64-musl": "1.3.96", + "@swc/core-linux-x64-gnu": "1.3.96", + "@swc/core-linux-x64-musl": "1.3.96", + "@swc/core-win32-arm64-msvc": "1.3.96", + "@swc/core-win32-ia32-msvc": "1.3.96", + "@swc/core-win32-x64-msvc": "1.3.96" + }, + "peerDependencies": { + "@swc/helpers": "^0.5.0" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } } }, - "node_modules/@tarojs/binding-darwin-arm64": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tarojs/binding-darwin-arm64/-/binding-darwin-arm64-4.2.1.tgz", - "integrity": "sha512-1kEzEd49JayLRHfudaVAQnceO8ircCDjvZs5GahUgTQi2Fk4L3wEPnslwCyX8hKeoVjqZoxaAY7yOpYcSjTW8w==", + "node_modules/@swc/core-darwin-arm64": { + "version": "1.3.96", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.96.tgz", + "integrity": "sha512-8hzgXYVd85hfPh6mJ9yrG26rhgzCmcLO0h1TIl8U31hwmTbfZLzRitFQ/kqMJNbIBCwmNH1RU2QcJnL3d7f69A==", "cpu": [ "arm64" ], - "dev": true, - "license": "MIT", + "license": "Apache-2.0 AND MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">= 18" + "node": ">=10" } }, - "node_modules/@tarojs/binding-darwin-x64": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tarojs/binding-darwin-x64/-/binding-darwin-x64-4.2.1.tgz", - "integrity": "sha512-mNBsSSar/7M+rjJWPTOBL6tt8Mli+Y9XhYgAqLTzDlzAscA5YlHcTv514m+T413dKR41CsZT8MmAKocxOxPvZQ==", + "node_modules/@swc/core-darwin-x64": { + "version": "1.3.96", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.96.tgz", + "integrity": "sha512-mFp9GFfuPg+43vlAdQZl0WZpZSE8sEzqL7sr/7Reul5McUHP0BaLsEzwjvD035ESfkY8GBZdLpMinblIbFNljQ==", "cpu": [ "x64" ], - "dev": true, - "license": "MIT", + "license": "Apache-2.0 AND MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">= 18" + "node": ">=10" } }, - "node_modules/@tarojs/binding-linux-arm64-gnu": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tarojs/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-4.2.1.tgz", - "integrity": "sha512-OEnKiTXkR62r6KRp0qhkiB2SqvS9pUzmDTcK2IeKb3tADiOMFOdLX6xpfFp9K2X/+STHpfW76QxPuF1fUpPNBg==", + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.3.96", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.96.tgz", + "integrity": "sha512-8UEKkYJP4c8YzYIY/LlbSo8z5Obj4hqcv/fUTHiEePiGsOddgGf7AWjh56u7IoN/0uEmEro59nc1ChFXqXSGyg==", "cpu": [ - "arm64" + "arm" ], - "dev": true, - "license": "MIT", + "license": "Apache-2.0 AND MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">= 18" + "node": ">=10" } }, - "node_modules/@tarojs/binding-linux-x64-gnu": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tarojs/binding-linux-x64-gnu/-/binding-linux-x64-gnu-4.2.1.tgz", - "integrity": "sha512-doHJRy4QZ2MmWXfr8uMWIsQzN+whUpnYSDvljkFzdiIDlDGtOHQnDKbVkPQc9fNaFPg9YAP3FGJnGZ0dF6TlhQ==", + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.3.96", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.96.tgz", + "integrity": "sha512-c/IiJ0s1y3Ymm2BTpyC/xr6gOvoqAVETrivVXHq68xgNms95luSpbYQ28rqaZC8bQC8M5zdXpSc0T8DJu8RJGw==", "cpu": [ - "x64" + "arm64" ], - "dev": true, - "license": "MIT", + "license": "Apache-2.0 AND MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">= 18" + "node": ">=10" } }, - "node_modules/@tarojs/binding-win32-x64-msvc": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tarojs/binding-win32-x64-msvc/-/binding-win32-x64-msvc-4.2.1.tgz", - "integrity": "sha512-dWJnwfKSXgcERKOQ5KUGbQTyw7ZOZ738p88vQC8ZBiOpJHNlNX+bFuHMAxM9ncUjUdk6SF+rz5vVPB0+LzfmWg==", + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.3.96", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.96.tgz", + "integrity": "sha512-i5/UTUwmJLri7zhtF6SAo/4QDQJDH2fhYJaBIUhrICmIkRO/ltURmpejqxsM/ye9Jqv5zG7VszMC0v/GYn/7BQ==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.3.96", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.96.tgz", + "integrity": "sha512-USdaZu8lTIkm4Yf9cogct/j5eqtdZqTgcTib4I+NloUW0E/hySou3eSyp3V2UAA1qyuC72ld1otXuyKBna0YKQ==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.3.96", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.96.tgz", + "integrity": "sha512-QYErutd+G2SNaCinUVobfL7jWWjGTI0QEoQ6hqTp7PxCJS/dmKmj3C5ZkvxRYcq7XcZt7ovrYCTwPTHzt6lZBg==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.3.96", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.96.tgz", + "integrity": "sha512-hjGvvAduA3Un2cZ9iNP4xvTXOO4jL3G9iakhFsgVhpkU73SGmK7+LN8ZVBEu4oq2SUcHO6caWvnZ881cxGuSpg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.3.96", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.96.tgz", + "integrity": "sha512-Far2hVFiwr+7VPCM2GxSmbh3ikTpM3pDombE+d69hkedvYHYZxtTF+2LTKl/sXtpbUnsoq7yV/32c9R/xaaWfw==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.3.96", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.96.tgz", + "integrity": "sha512-4VbSAniIu0ikLf5mBX81FsljnfqjoVGleEkCQv4+zRlyZtO3FHoDPkeLVoy6WRlj7tyrRcfUJ4mDdPkbfTO14g==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "license": "Apache-2.0" + }, + "node_modules/@swc/register": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/@swc/register/-/register-0.1.10.tgz", + "integrity": "sha512-6STwH/q4dc3pitXLVkV7sP0Hiy+zBsU2wOF1aXpXR95pnH3RYHKIsDC+gvesfyB7jxNT9OOZgcqOp9RPxVTx9A==", + "deprecated": "Use @swc-node/register instead", + "license": "(Apache-2.0 OR MIT)", + "dependencies": { + "lodash.clonedeep": "^4.5.0", + "pirates": "^4.0.1", + "source-map-support": "^0.5.13" + }, + "bin": { + "swc-node": "bin/swc-node" + }, + "peerDependencies": { + "@swc/core": "^1.0.46" + } + }, + "node_modules/@swc/types": { + "version": "0.1.28", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.28.tgz", + "integrity": "sha512-V6Mnml8v09QALx6K0elJ7o9K/MkVDtW3t6L+7Ou/JcWtb3xwId2AH4FeOceySd2JaO87IMw4+6vSZxLm34LPbw==", + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "defer-to-connect": "^1.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@tarojs/api": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tarojs/api/-/api-4.2.1.tgz", + "integrity": "sha512-GlgqH/mx0EC+tYrcUnqa7vsGSOaAzIJNxvDcUESO6FiKb1xLESGmgGbaiEkqw29Nx/3j3lEXjHrCHJUdGy3X2Q==", + "license": "MIT", + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@tarojs/runtime": "4.2.1", + "@tarojs/shared": "4.2.1" + } + }, + "node_modules/@tarojs/binding": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tarojs/binding/-/binding-4.2.1.tgz", + "integrity": "sha512-Sg4+gj00Fn8rKiUIeoS18jQtJVvc9TzK4BzwAEOwUaTBISU/PYCoXm5Sjuz4mN9jaaRuyCgzJ0NTkxOAjdY7Mg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@napi-rs/triples": "1.2.0" + }, + "optionalDependencies": { + "@tarojs/binding-darwin-arm64": "4.2.1", + "@tarojs/binding-darwin-x64": "4.2.1", + "@tarojs/binding-linux-arm64-gnu": "4.2.1", + "@tarojs/binding-linux-x64-gnu": "4.2.1", + "@tarojs/binding-win32-x64-msvc": "4.2.1" + } + }, + "node_modules/@tarojs/binding-darwin-arm64": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tarojs/binding-darwin-arm64/-/binding-darwin-arm64-4.2.1.tgz", + "integrity": "sha512-1kEzEd49JayLRHfudaVAQnceO8ircCDjvZs5GahUgTQi2Fk4L3wEPnslwCyX8hKeoVjqZoxaAY7yOpYcSjTW8w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 18" + } + }, + "node_modules/@tarojs/binding-darwin-x64": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tarojs/binding-darwin-x64/-/binding-darwin-x64-4.2.1.tgz", + "integrity": "sha512-mNBsSSar/7M+rjJWPTOBL6tt8Mli+Y9XhYgAqLTzDlzAscA5YlHcTv514m+T413dKR41CsZT8MmAKocxOxPvZQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 18" + } + }, + "node_modules/@tarojs/binding-linux-arm64-gnu": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tarojs/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-4.2.1.tgz", + "integrity": "sha512-OEnKiTXkR62r6KRp0qhkiB2SqvS9pUzmDTcK2IeKb3tADiOMFOdLX6xpfFp9K2X/+STHpfW76QxPuF1fUpPNBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 18" + } + }, + "node_modules/@tarojs/binding-linux-x64-gnu": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tarojs/binding-linux-x64-gnu/-/binding-linux-x64-gnu-4.2.1.tgz", + "integrity": "sha512-doHJRy4QZ2MmWXfr8uMWIsQzN+whUpnYSDvljkFzdiIDlDGtOHQnDKbVkPQc9fNaFPg9YAP3FGJnGZ0dF6TlhQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 18" + } + }, + "node_modules/@tarojs/binding-win32-x64-msvc": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tarojs/binding-win32-x64-msvc/-/binding-win32-x64-msvc-4.2.1.tgz", + "integrity": "sha512-dWJnwfKSXgcERKOQ5KUGbQTyw7ZOZ738p88vQC8ZBiOpJHNlNX+bFuHMAxM9ncUjUdk6SF+rz5vVPB0+LzfmWg==", "cpu": [ "x64" ], @@ -3839,7 +4495,6 @@ "resolved": "https://registry.npmjs.org/@tarojs/helper/-/helper-4.2.1.tgz", "integrity": "sha512-v1kvcOn+nyJkt27N/n4Y16tBqqLM5oXiEcFZA6oKKvxibCMJS2IWeCnjcyj/FFNFFzu7Oqo1sEDuSxBc71IDRQ==", "license": "MIT", - "peer": true, "dependencies": { "@babel/core": "^7.24.4", "@babel/generator": "^7.24.4", @@ -4072,17 +4727,114 @@ "node": ">= 10" } }, - "node_modules/@tarojs/plugin-framework-react": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tarojs/plugin-framework-react/-/plugin-framework-react-4.2.1.tgz", - "integrity": "sha512-+ZOpFIkdb75eWbFkRbFz81R9qHp/sUgfr4UPZCntaxvUXyAZrCjcYd6IsGLjg/563WG/BjRS0tdkEnmp8bOnPQ==", + "node_modules/@tarojs/plugin-doctor/node_modules/@eslint/js": { + "version": "8.41.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.41.0.tgz", + "integrity": "sha512-LxcyMGxwmTh2lY9FwHPGWOHmYFCZvbrFCBZL4FzSSsxsRPuhrYUg/49/0KDfW8tnIEaEHtfmn6+NPN+1DqaNmA==", + "dev": true, "license": "MIT", - "dependencies": { - "acorn": "^8.11.3", - "acorn-walk": "^8.3.2", - "lodash": "^4.17.21", - "tslib": "^2.6.2" - }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@tarojs/plugin-doctor/node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@tarojs/plugin-doctor/node_modules/eslint": { + "version": "8.41.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.41.0.tgz", + "integrity": "sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "@eslint/eslintrc": "^2.0.3", + "@eslint/js": "8.41.0", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.0", + "eslint-visitor-keys": "^3.4.1", + "espree": "^9.5.2", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@tarojs/plugin-doctor/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@tarojs/plugin-framework-react": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tarojs/plugin-framework-react/-/plugin-framework-react-4.2.1.tgz", + "integrity": "sha512-+ZOpFIkdb75eWbFkRbFz81R9qHp/sUgfr4UPZCntaxvUXyAZrCjcYd6IsGLjg/563WG/BjRS0tdkEnmp8bOnPQ==", + "license": "MIT", + "dependencies": { + "acorn": "^8.11.3", + "acorn-walk": "^8.3.2", + "lodash": "^4.17.21", + "tslib": "^2.6.2" + }, "engines": { "node": ">= 18" }, @@ -4217,7 +4969,6 @@ "resolved": "https://registry.npmjs.org/@tarojs/runtime/-/runtime-4.2.1.tgz", "integrity": "sha512-7PgK9ohtmkTkY1zINx8hTQ8pe/1Ees8bYYkcb5w/pP+MnJt27xpKli3Tyeq6+wKwAHL58om+MizCz215SXoVcw==", "license": "MIT", - "peer": true, "dependencies": { "@tarojs/shared": "4.2.1", "tslib": "^2.6.2" @@ -4231,7 +4982,6 @@ "resolved": "https://registry.npmjs.org/@tarojs/service/-/service-4.2.1.tgz", "integrity": "sha512-d3xHGyJQBsMmYp6ajqR2DyykQb5rave9Sy1Nry737t47YK9r3upPdeHdsYC96TQORK0DfiJd1ZH6j62IkVXXfw==", "license": "MIT", - "peer": true, "dependencies": { "@tarojs/helper": "4.2.1", "@tarojs/runner-utils": "4.2.1", @@ -4252,7 +5002,6 @@ "resolved": "https://registry.npmjs.org/@tarojs/shared/-/shared-4.2.1.tgz", "integrity": "sha512-rAQxBt490zjU9T7qGVmHivfVH1O02oQX7ZtaxVEEguwxVBqo4kr8hNs9v3OyPP4LiyROrwszT70cDkuynHpLUA==", "license": "MIT", - "peer": true, "engines": { "node": ">= 18" } @@ -4262,7 +5011,6 @@ "resolved": "https://registry.npmjs.org/@tarojs/taro/-/taro-4.2.1.tgz", "integrity": "sha512-xH8vHwrydO8YonwhEcQ1E61wvm5c5NevLKXQUTSYjze0lu0D4WqH9qSjEiCCIHtZ6KTJ/2Cvs8/murq14Z//IQ==", "license": "MIT", - "peer": true, "dependencies": { "@tarojs/api": "4.2.1", "@tarojs/runtime": "4.2.1", @@ -4482,8 +5230,7 @@ "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.20.tgz", "integrity": "sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@types/chai-subset": { "version": "1.3.6", @@ -4670,6 +5417,13 @@ "devOptional": true, "license": "MIT" }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/lodash": { "version": "4.17.25", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.25.tgz", @@ -4705,9 +5459,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.19.19", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.19.tgz", - "integrity": "sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==", + "version": "22.18.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.6.tgz", + "integrity": "sha512-r8uszLPpeIWbNKtvWRt/DbVi5zbqZyj1PTmhRMqBMvDnaz1QpmSKujUtJLrqGZeoM8v72MfYggDceY4K1itzWQ==", "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -4760,22 +5514,11 @@ "integrity": "sha512-0dLEBsA1kI3OezMBF8nSsb7Nk19ZnsyE1LLhB8r27KbgU5H4pvuqZLdtE+aUkJVoXgTVuA+iLIwmZ0TuK4tx6A==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" } }, - "node_modules/@types/react-dom": { - "version": "18.3.7", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", - "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@types/react": "^18.0.0" - } - }, "node_modules/@types/retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", @@ -4792,6 +5535,13 @@ "@types/node": "*" } }, + "node_modules/@types/semver": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-1mAINjtQCXXeLkJ9ehXkwOcBpqtLxiVtKhpUf83DdRNdQKV0iXZpaHYqRr7nj+wvxuJzoAmAwXI+sCNMv1CzLQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/send": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", @@ -4845,6 +5595,13 @@ "@types/node": "*" } }, + "node_modules/@types/webpack-env": { + "version": "1.18.8", + "resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.18.8.tgz", + "integrity": "sha512-G9eAoJRMLjcvN4I08wB5I7YofOb/kaJNd5uoCMX+LbKXTPCF+ZIHuqTnFaK9Jz1rgs035f9JUPUhNFtqgucy/A==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/ws": { "version": "8.18.1", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", @@ -4872,123 +5629,424 @@ "dev": true, "license": "MIT" }, - "node_modules/@vitest/expect": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.34.6.tgz", - "integrity": "sha512-QUzKpUQRc1qC7qdGo7rMK3AkETI7w18gTCUrsNnyjjJKYiuUB9+TQK3QnR1unhCnWRC0AbKv2omLGQDF/mIjOw==", + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", + "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "0.34.6", - "@vitest/utils": "0.34.6", - "chai": "^4.3.10" + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/type-utils": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" }, "funding": { - "url": "https://opencollective.com/vitest" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@vitest/runner": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.34.6.tgz", - "integrity": "sha512-1CUQgtJSLF47NnhN+F9X2ycxUP0kLHQ/JWvNHbeBfwW8CzEGgeskzNnHDyv1ieKTltuR6sdIHV+nmR6kPxQqzQ==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/utils": "0.34.6", - "p-limit": "^4.0.0", - "pathe": "^1.1.1" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" }, - "funding": { - "url": "https://opencollective.com/vitest" + "engines": { + "node": ">=10" } }, - "node_modules/@vitest/runner/node_modules/p-limit": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", - "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "node_modules/@typescript-eslint/parser": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", + "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "yocto-queue": "^1.0.0" + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@vitest/runner/node_modules/yocto-queue": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", - "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", + "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", "dev": true, "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" + }, "engines": { - "node": ">=12.20" + "node": "^16.0.0 || >=18.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@vitest/snapshot": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-0.34.6.tgz", - "integrity": "sha512-B3OZqYn6k4VaN011D+ve+AA4whM4QkcwcrwaKwAbyyvS/NB1hCWjFIBQxAQQSQir9/RtyAAGuq+4RJmbn2dH4w==", + "node_modules/@typescript-eslint/type-utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", + "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", "dev": true, "license": "MIT", "dependencies": { - "magic-string": "^0.30.1", - "pathe": "^1.1.1", - "pretty-format": "^29.5.0" + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" }, "funding": { - "url": "https://opencollective.com/vitest" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@vitest/snapshot/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "node_modules/@typescript-eslint/types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", + "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", "dev": true, "license": "MIT", "engines": { - "node": ">=10" + "node": "^16.0.0 || >=18.0.0" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@vitest/snapshot/node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", + "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@vitest/snapshot/node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", + "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } }, - "node_modules/@vitest/spy": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.34.6.tgz", - "integrity": "sha512-xaCvneSaeBw/cz8ySmF7ZwGvL0lBjfvqc1LpQ/vcdHEvpLn3Ff1vAvjw+CoGn0802l++5L/pxb7whwcWAw+DUQ==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, "license": "MIT", "dependencies": { - "tinyspy": "^2.1.1" + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", + "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", + "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.3.tgz", + "integrity": "sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==", + "dev": true, + "license": "ISC" + }, + "node_modules/@vitest/expect": { + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.34.6.tgz", + "integrity": "sha512-QUzKpUQRc1qC7qdGo7rMK3AkETI7w18gTCUrsNnyjjJKYiuUB9+TQK3QnR1unhCnWRC0AbKv2omLGQDF/mIjOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "0.34.6", + "@vitest/utils": "0.34.6", + "chai": "^4.3.10" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.34.6.tgz", + "integrity": "sha512-1CUQgtJSLF47NnhN+F9X2ycxUP0kLHQ/JWvNHbeBfwW8CzEGgeskzNnHDyv1ieKTltuR6sdIHV+nmR6kPxQqzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "0.34.6", + "p-limit": "^4.0.0", + "pathe": "^1.1.1" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@vitest/runner/node_modules/yocto-queue": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", + "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@vitest/snapshot": { + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-0.34.6.tgz", + "integrity": "sha512-B3OZqYn6k4VaN011D+ve+AA4whM4QkcwcrwaKwAbyyvS/NB1hCWjFIBQxAQQSQir9/RtyAAGuq+4RJmbn2dH4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "magic-string": "^0.30.1", + "pathe": "^1.1.1", + "pretty-format": "^29.5.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@vitest/snapshot/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@vitest/snapshot/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vitest/spy": { + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.34.6.tgz", + "integrity": "sha512-xaCvneSaeBw/cz8ySmF7ZwGvL0lBjfvqc1LpQ/vcdHEvpLn3Ff1vAvjw+CoGn0802l++5L/pxb7whwcWAw+DUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^2.1.1" }, "funding": { "url": "https://opencollective.com/vitest" @@ -5226,34 +6284,27 @@ "license": "MIT" }, "node_modules/accepts": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", - "dev": true, + "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==", + "devOptional": true, "license": "MIT", "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" + "mime-types": "~2.1.34", + "negotiator": "0.6.3" }, "engines": { "node": ">= 0.6" } }, - "node_modules/accepts/node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", - "dev": true, + "node_modules/accepts/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==", + "devOptional": true, "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "node": ">= 0.6" } }, "node_modules/acorn": { @@ -5261,7 +6312,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -5370,7 +6420,6 @@ "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -5383,10 +6432,10 @@ } }, "node_modules/ajv-formats": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", - "dev": true, + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "devOptional": true, "license": "MIT", "dependencies": { "ajv": "^8.0.0" @@ -5404,7 +6453,7 @@ "version": "8.20.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -5421,7 +6470,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/ajv-keywords": { @@ -5449,6 +6498,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ansi-html": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.9.tgz", + "integrity": "sha512-ozbS3LuenHVxNRh/wdnN16QapUHzauqSomAl1jwwJRRsGwFwtj644lIhxfWu0Fy0acCij2+AEgHvjscq3dlVXg==", + "devOptional": true, + "engines": [ + "node >= 0.8.0" + ], + "license": "Apache-2.0", + "bin": { + "ansi-html": "bin/ansi-html" + } + }, "node_modules/ansi-html-community": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", @@ -5561,6 +6623,23 @@ "dev": true, "license": "Python-2.0" }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -5568,9 +6647,175 @@ "devOptional": true, "license": "MIT" }, - "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "node_modules/array-includes": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", + "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", + "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-shim-unscopables": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.toreversed": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz", + "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", "dev": true, "license": "MIT", @@ -5578,6 +6823,16 @@ "node": "*" } }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/async-limiter": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", @@ -5810,13 +7065,6 @@ "node": ">=6.9.0" } }, - "node_modules/babel-plugin-transform-solid-jsx/node_modules/html-entities": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", - "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==", - "dev": true, - "license": "MIT" - }, "node_modules/babel-plugin-transform-taroapi": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-taroapi/-/babel-plugin-transform-taroapi-4.2.1.tgz", @@ -5887,21 +7135,6 @@ } } }, - "node_modules/babel-preset-taro/node_modules/core-js": { - "version": "3.50.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.50.0.tgz", - "integrity": "sha512-BRWgOLKkFeCgRudR6zrs8p9XJZcE14grzKMMssoYrk6krtuEZ7MTKPIY5RzOnqsEKIR9kst7wNzphttraT+Yqw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "engines": { - "node": "*" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -5951,7 +7184,7 @@ "version": "5.2.2", "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": "*" @@ -6002,44 +7235,60 @@ "license": "MIT" }, "node_modules/body-parser": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz", - "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", - "dev": true, + "version": "1.20.6", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.6.tgz", + "integrity": "sha512-p5tAzS57i5MV9fZFDj9LeIiTZEufbSe2eDozP+ElheSUq1m74CRq1jI4mYNDdVs9vQztXFLuk/Gd6BWTdwRJ5g==", + "devOptional": true, "license": "MIT", "dependencies": { - "bytes": "^3.1.2", - "content-type": "^2.0.0", - "debug": "^4.4.3", - "http-errors": "^2.0.1", - "iconv-lite": "^0.7.2", - "on-finished": "^2.4.1", - "qs": "^6.15.2", - "raw-body": "^3.0.2", - "type-is": "^2.1.0" + "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": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/body-parser/node_modules/content-type": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", - "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", - "dev": true, + "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==", + "devOptional": true, "license": "MIT", - "engines": { - "node": ">=18" + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/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==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "engines": { + "node": ">=0.10.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==", + "devOptional": true, + "license": "MIT" + }, "node_modules/bonjour-service": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.4.4.tgz", @@ -6099,7 +7348,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.11.12", "caniuse-lite": "^1.0.30001809", @@ -6773,16 +8021,6 @@ "devOptional": true, "license": "MIT" }, - "node_modules/compression/node_modules/negotiator": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", - "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", - "devOptional": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -6875,14 +8113,11 @@ } }, "node_modules/cookie-signature": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.6.0" - } + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", + "devOptional": true, + "license": "MIT" }, "node_modules/copy-anything": { "version": "3.0.5", @@ -6890,6 +8125,7 @@ "integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "is-what": "^4.1.8" }, @@ -6931,7 +8167,6 @@ "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -6943,24 +8178,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/copy-webpack-plugin/node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, "node_modules/copy-webpack-plugin/node_modules/ajv-keywords": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", @@ -7015,18 +8232,24 @@ } }, "node_modules/core-js": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", - "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", - "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", - "dev": true, - "hasInstallScript": true, - "license": "MIT" - }, - "node_modules/core-js-compat": { "version": "3.50.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.50.0.tgz", - "integrity": "sha512-XGpFGbMLHwSt74YLTKho7Ib242qi6O8MSX+sRokV4oz7iKXvQWGYZthjIhjRGMxjzVkAubBO512dKGYcefmX3Q==", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.50.0.tgz", + "integrity": "sha512-BRWgOLKkFeCgRudR6zrs8p9XJZcE14grzKMMssoYrk6krtuEZ7MTKPIY5RzOnqsEKIR9kst7wNzphttraT+Yqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat": { + "version": "3.50.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.50.0.tgz", + "integrity": "sha512-XGpFGbMLHwSt74YLTKho7Ib242qi6O8MSX+sRokV4oz7iKXvQWGYZthjIhjRGMxjzVkAubBO512dKGYcefmX3Q==", "dev": true, "license": "MIT", "dependencies": { @@ -7044,7 +8267,7 @@ "version": "3.50.0", "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.50.0.tgz", "integrity": "sha512-6GP3Pxz4IKyWjAfa747vIu/jilB5z29JWROLqH/b+pXVcpgh6tM06ZIBwSuglgVqzDYURhOK6oEzTrG0bCHitA==", - "dev": true, + "devOptional": true, "hasInstallScript": true, "license": "MIT", "engines": { @@ -7062,24 +8285,6 @@ "devOptional": true, "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, "node_modules/cosmiconfig": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.2.tgz", @@ -7244,7 +8449,6 @@ "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -7256,24 +8460,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/css-minimizer-webpack-plugin/node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, "node_modules/css-minimizer-webpack-plugin/node_modules/ajv-keywords": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", @@ -7521,6 +8707,60 @@ "node": ">=18" } }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -7900,7 +9140,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "engines": { "node": ">=8" @@ -7950,6 +9190,29 @@ "promise-polyfill": "^7.1.0" } }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dir-glob/node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/dns-packet": { "version": "5.6.1", "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", @@ -8213,7 +9476,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">= 4" @@ -8310,6 +9573,104 @@ "is-arrayish": "^0.2.1" } }, + "node_modules/error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "stackframe": "^1.3.4" + } + }, + "node_modules/es-abstract": { + "version": "1.24.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.2.tgz", + "integrity": "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-abstract-get": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-abstract-get/-/es-abstract-get-1.0.0.tgz", + "integrity": "sha512-6PMWXpdhshVvFp+FoWYs1EvG1Nj0tvk0dZM+XcK0xMEM1czRVcP6ohqPWHy6qPagSpC8j4+p89WXlT+xXJs/fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.2", + "is-callable": "^1.2.7", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", @@ -8329,6 +9690,34 @@ "node": ">= 0.4" } }, + "node_modules/es-iterator-helpers": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.4.0.tgz", + "integrity": "sha512-c/A0P0oxkACDc+cKWw8evLXK83oBKgn0qPOqCYT4x9uolpCIJAcYvJC9QYKNDRPsTeGyCrQ326jrvgZWdCdK5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.2", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.1.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.3.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "iterator.prototype": "^1.1.5", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-module-lexer": { "version": "0.10.5", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.10.5.tgz", @@ -8365,6 +9754,40 @@ "node": ">= 0.4" } }, + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.4.tgz", + "integrity": "sha512-yPDz7wqpg1/mmHLmS3tcfTfbw5f1eryXvyghYBffGdERwe+mV7ZcWzTR8LR17Kvqt3qfPurjlonmnq3MKXIOXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-abstract-get": "^1.0.0", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "is-callable": "^1.2.7", + "is-date-object": "^1.1.0", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/esbuild": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", @@ -8900,30 +10323,30 @@ } }, "node_modules/eslint": { - "version": "8.41.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.41.0.tgz", - "integrity": "sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.3", - "@eslint/js": "8.41.0", - "@humanwhocodes/config-array": "^0.11.8", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.0", - "eslint-visitor-keys": "^3.4.1", - "espree": "^9.5.2", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -8933,7 +10356,6 @@ "globals": "^13.19.0", "graphemer": "^1.4.0", "ignore": "^5.2.0", - "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", @@ -8943,9 +10365,8 @@ "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", + "optionator": "^0.9.3", "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" }, "bin": { @@ -8958,50 +10379,297 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "node_modules/eslint-config-taro": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-config-taro/-/eslint-config-taro-4.2.1.tgz", + "integrity": "sha512-tO9QrjI9tWQXHdktelikOjvlbpGIMnzL2mLp6s7ETn4NL45NzVRmXJHL3Y89IuByywhrQtNSgGmhAiUk7KIS7Q==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "@babel/eslint-parser": "^7.24.1", + "@typescript-eslint/eslint-plugin": "^6.2.0", + "@typescript-eslint/parser": "^6.2.0", + "eslint-plugin-import": "^2.29.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">= 18" }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "peerDependencies": { + "eslint": "^8", + "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react-hooks": "^4.4.0", + "eslint-plugin-vue": "^8.0.0" }, - "funding": { - "url": "https://opencollective.com/eslint" + "peerDependenciesMeta": { + "eslint-plugin-react": { + "optional": true + }, + "eslint-plugin-react-hooks": { + "optional": true + }, + "eslint-plugin-vue": { + "optional": true + } } }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "node_modules/eslint-import-resolver-node": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.10.tgz", + "integrity": "sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" + "debug": "^3.2.7", + "is-core-module": "^2.16.1", + "resolve": "^2.0.0-next.6" } }, - "node_modules/espree": { + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/resolve": { + "version": "2.0.0-next.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.7.tgz", + "integrity": "sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.2", + "node-exports-info": "^1.6.0", + "object-keys": "^1.1.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.14.0.tgz", + "integrity": "sha512-W2WCRZ9Dqntd+2u8jJcVMV2PKulc6RdLgUUoh/yQr3uB6lo/ZOeGx11sv60/8S4QFFKNslAlWhr9u0Ef7ZW6Ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.32.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", + "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.9", + "array.prototype.findlastindex": "^1.2.6", + "array.prototype.flat": "^1.3.3", + "array.prototype.flatmap": "^1.3.3", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.12.1", + "hasown": "^2.0.2", + "is-core-module": "^2.16.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.1", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.9", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.34.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz", + "integrity": "sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlast": "^1.2.4", + "array.prototype.flatmap": "^1.3.2", + "array.prototype.toreversed": "^1.1.2", + "array.prototype.tosorted": "^1.1.3", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.0.17", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.7", + "object.fromentries": "^2.0.7", + "object.hasown": "^1.1.3", + "object.values": "^1.1.7", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.10" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.4.0.tgz", + "integrity": "sha512-U3RVIfdzJaeKDQKEJbz5p3NW8/L80PCATJAfuojwbaEL+gBjfGdhUcGde+WGUW46Q5sr/NgxevsIiDtNXrvZaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.7.tgz", + "integrity": "sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.2", + "node-exports-info": "^1.6.0", + "object-keys": "^1.1.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", @@ -9092,29 +10760,6 @@ "node": ">=0.8.x" } }, - "node_modules/eventsource": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", - "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eventsource-parser": "^3.0.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/eventsource-parser": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.1.1.tgz", - "integrity": "sha512-EKN1vKAMcZ8MlYMpaNuxN6R9yakzH6uajHcHVTqWJzvu5pWw9DyhbP35HH8MVBQ+dZjAfDxk+A8NiR9KWaXiyQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.0.0" - } - }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -9186,99 +10831,75 @@ "license": "MIT" }, "node_modules/express": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", - "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "accepts": "^2.0.0", - "body-parser": "^2.2.1", - "content-disposition": "^1.0.0", - "content-type": "^1.0.5", - "cookie": "^0.7.1", - "cookie-signature": "^1.2.1", - "debug": "^4.4.0", - "depd": "^2.0.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "finalhandler": "^2.1.0", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "merge-descriptors": "^2.0.0", - "mime-types": "^3.0.0", - "on-finished": "^2.4.1", - "once": "^1.4.0", - "parseurl": "^1.3.3", - "proxy-addr": "^2.0.7", - "qs": "^6.14.0", - "range-parser": "^1.2.1", - "router": "^2.2.0", - "send": "^1.1.0", - "serve-static": "^2.2.0", - "statuses": "^2.0.1", - "type-is": "^2.0.1", - "vary": "^1.1.2" + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.2.tgz", + "integrity": "sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q==", + "devOptional": true, + "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": ">= 18" + "node": ">= 0.10.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/express" } }, - "node_modules/express-rate-limit": { - "version": "8.6.2", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.6.2.tgz", - "integrity": "sha512-YH4ru+eOJxQABscKFfRCy9R7x9QFGdezclVMwwgFFndzS2Xnm0uo6B0ABZsLhcpeptGv2qvuJVWlQr9gQZoC3A==", - "dev": true, + "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==", + "devOptional": true, "license": "MIT", "dependencies": { - "debug": "^4.4.3", - "ip-address": "^10.2.0" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/express-rate-limit" - }, - "peerDependencies": { - "express": ">= 4.11" + "ms": "2.0.0" } }, - "node_modules/express/node_modules/content-disposition": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", - "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } + "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==", + "devOptional": true, + "license": "MIT" }, - "node_modules/express/node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } + "node_modules/express/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==", + "devOptional": true, + "license": "MIT" }, "node_modules/ext-list": { "version": "2.2.2", @@ -9494,27 +11115,41 @@ } }, "node_modules/finalhandler": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", - "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", - "dev": true, + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", + "devOptional": true, "license": "MIT", "dependencies": { - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "on-finished": "^2.4.1", - "parseurl": "^1.3.3", - "statuses": "^2.0.1" + "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": ">= 18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "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==", + "devOptional": true, + "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==", + "devOptional": true, + "license": "MIT" + }, "node_modules/find-cache-dir": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", @@ -9683,13 +11318,13 @@ } }, "node_modules/fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", - "dev": true, + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "devOptional": true, "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">= 0.6" } }, "node_modules/from2": { @@ -9760,6 +11395,50 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/function.prototype.name": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.2.0.tgz", + "integrity": "sha512-jObKIik1P2QjPHP5nz5BaOtUlfgS0fWo8IUByNXkM+o+02sJOi94em77GwJKQSJ3gfPHdgzLNrHc1uokV4P/ew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2", + "hasown": "^2.0.4", + "is-callable": "^1.2.7", + "is-document.all": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -9851,6 +11530,24 @@ "node": ">=4" } }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/get-tsconfig": { "version": "4.14.3", "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.3.tgz", @@ -9980,6 +11677,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/globby": { "version": "14.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-14.1.0.tgz", @@ -10128,6 +11842,19 @@ "integrity": "sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g==", "license": "(Apache-2.0 OR MPL-1.1)" }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -10150,6 +11877,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-symbol-support-x": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", @@ -10259,17 +12002,6 @@ "integrity": "sha512-DlzIkeBAS9IIQ432k3BUf3HlwbsR0+trB1i2lDdN2gUkNkrehFurh0/48M5c1/EjlDkdGng1gwZIpwyPxvdZ/g==", "license": "Apache-2.0" }, - "node_modules/hono": { - "version": "4.13.5", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.13.5.tgz", - "integrity": "sha512-O6+/eCYRkzzzy0rPWwKLiGBR1nFuUPZynnwjxN1MBA62NNqbT0wQEzQyK2gSO5yDIDB336sXQleAhOHrzlYyKw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=16.9.0" - } - }, "node_modules/hpack.js": { "version": "2.1.6", "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", @@ -10297,20 +12029,10 @@ } }, "node_modules/html-entities": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", - "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", + "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==", "devOptional": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/mdevils" - }, - { - "type": "patreon", - "url": "https://patreon.com/mdevils" - } - ], "license": "MIT" }, "node_modules/html-minifier": { @@ -10431,7 +12153,6 @@ "integrity": "sha512-MZmKQcTnhEh1SPSyMiEytIeDZDUoBZVorNHivQGXMASHf/BSGGOrKa2xQ5bGx3TCe1n109ecCt+cpww7wwWhKA==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "@types/html-minifier-terser": "^6.0.0", "html-minifier-terser": "^6.0.2", @@ -10720,9 +12441,9 @@ } }, "node_modules/immutable": { - "version": "4.3.9", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.9.tgz", - "integrity": "sha512-ObHy4YN7ycwZOUCLI1/6svfyAFu7vL8RhAvVu/bh/RZW9EPlOyDaQ9jDQWCtdqzaXUjgXZCW1migtHE7YI7UGQ==", + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.9.tgz", + "integrity": "sha512-m8nVez3rwrgmWxtLMt1ZYXB2Lv7OKYn/disyxAlSDYAlKSlFoPPfIAmAM/M5xqL4m4C/wAPw7S2/CNaUii1Hxg==", "license": "MIT" }, "node_modules/import-fresh": { @@ -10803,6 +12524,21 @@ "node": ">=12.0.0" } }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/into-stream": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz", @@ -10817,24 +12553,32 @@ "node": ">=4" } }, - "node_modules/ip-address": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.5.0.tgz", - "integrity": "sha512-R5SnVLJmgYYvf2F2ZgwSBnelz5G4q5AxIC277GDfUaNbrZKNANcBC7RHqYYePlszf4kBolVkJauG0ZjHHFh55g==", - "dev": true, + "node_modules/ipaddr.js": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.5.0.tgz", + "integrity": "sha512-aq+t5NAc+cS6rZQQVWC2x98CPqGtKKTMDd4Gaodv0wShnItdKg/51djkGJ1hqH+Oy0ivDftCbSLCQob8zso01w==", + "devOptional": true, "license": "MIT", "engines": { - "node": ">= 12" + "node": ">= 10" } }, - "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==", - "devOptional": true, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, "engines": { - "node": ">= 0.10" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-arrayish": { @@ -10844,6 +12588,42 @@ "dev": true, "license": "MIT" }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -10856,6 +12636,23 @@ "node": ">=8" } }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", @@ -10891,31 +12688,98 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "devOptional": true, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, "license": "MIT", - "bin": { - "is-docker": "cli.js" + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" }, "engines": { - "node": ">=8" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "devOptional": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-document.all": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-document.all/-/is-document.all-1.0.0.tgz", + "integrity": "sha512-+XSoyS05OdBbhFuELhgTCpFNHkpBOJqtsZfUFFpe5QTw+9Sjbh8zitxhQkYAo6wV7e1Vb8cAPvpCk9jGam/82g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "license": "MIT", "engines": { "node": ">=0.10.0" } }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -10933,6 +12797,26 @@ "dev": true, "license": "MIT" }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -10964,6 +12848,19 @@ "node": ">=6.0" } }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-mobile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-mobile/-/is-mobile-4.0.0.tgz", @@ -10977,6 +12874,19 @@ "dev": true, "license": "MIT" }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -10986,6 +12896,23 @@ "node": ">=0.12.0" } }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-object": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz", @@ -11035,12 +12962,24 @@ "dev": true, "license": "MIT" }, - "node_modules/is-promise": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/is-retry-allowed": { "version": "1.2.0", @@ -11052,6 +12991,35 @@ "node": ">=0.10.0" } }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", @@ -11062,6 +13030,41 @@ "node": ">=0.10.0" } }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-typed-array": { "version": "1.1.15", "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", @@ -11090,12 +13093,59 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-what": { "version": "4.1.16", "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz", "integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12.13" }, @@ -11152,6 +13202,24 @@ "node": ">= 4" } }, + "node_modules/iterator.prototype": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", + "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "get-proto": "^1.0.0", + "has-symbols": "^1.1.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/j-component": { "version": "1.4.10", "resolved": "https://registry.npmjs.org/j-component/-/j-component-1.4.10.tgz", @@ -11267,6 +13335,15 @@ "regenerator-runtime": "^0.13.3" } }, + "node_modules/jimp/node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true, + "license": "MIT" + }, "node_modules/jimp/node_modules/regenerator-runtime": { "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", @@ -11297,16 +13374,6 @@ "@sideway/pinpoint": "^2.0.0" } }, - "node_modules/jose": { - "version": "6.2.10", - "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.10.tgz", - "integrity": "sha512-iiW7J9qRFlGxvCOIBDBDxFePQSn7ZMAnrYGhrrOo6siO/MIqwfyilLR27pkfDgUk+raLuzADS8A3S/KLBisc0g==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, "node_modules/jpeg-js": { "version": "0.3.7", "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.3.7.tgz", @@ -11467,13 +13534,6 @@ "devOptional": true, "license": "MIT" }, - "node_modules/json-schema-typed": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", - "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", - "dev": true, - "license": "BSD-2-Clause" - }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", @@ -11514,6 +13574,22 @@ "object-assign": "^4.1.1" } }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -11628,6 +13704,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">=18" }, @@ -12151,6 +14228,15 @@ "yallist": "^3.0.2" } }, + "node_modules/lucide-react": { + "version": "1.34.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.34.0.tgz", + "integrity": "sha512-vnjGJNI7Htk5+oWW8gXGuaLgwgAb0T6/iZbBrp9JCfRFwdNWZ0YTm3eyxjOLgwN6r8iyAf3UA70zNmBRBNv7yg==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/magic-string": { "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", @@ -12215,17 +14301,13 @@ "license": "MPL-2.0" }, "node_modules/media-typer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.1.tgz", - "integrity": "sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==", - "dev": true, + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "devOptional": true, "license": "MIT", "engines": { - "node": ">= 0.8" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "node": ">= 0.6" } }, "node_modules/memfs": { @@ -12242,14 +14324,11 @@ } }, "node_modules/merge-descriptors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", - "dev": true, + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "devOptional": true, "license": "MIT", - "engines": { - "node": ">=18" - }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } @@ -12408,7 +14487,6 @@ "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -12420,24 +14498,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/mini-css-extract-plugin/node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, "node_modules/mini-css-extract-plugin/node_modules/ajv-keywords": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", @@ -12539,35 +14599,6 @@ "ws": "^6.1.3" } }, - "node_modules/miniprogram-automator-mcp": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/miniprogram-automator-mcp/-/miniprogram-automator-mcp-0.1.1.tgz", - "integrity": "sha512-6ShG4mHVJ4NSLafD3HMUSTBylBpKDUd5+TFtu3LJO40NyGmIBum2JERtRFiw+0H0bN8NWBrpnSgTO38AnhtLzQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@modelcontextprotocol/sdk": "^1.17.5", - "commander": "^14.0.3", - "miniprogram-automator": "^0.12.1", - "zod": "^3.24.2" - }, - "bin": { - "miniprogram-automator-mcp": "bin/miniprogram-automator-mcp.js" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/miniprogram-automator-mcp/node_modules/commander": { - "version": "14.0.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", - "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - } - }, "node_modules/miniprogram-automator/node_modules/ws": { "version": "6.2.6", "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.6.tgz", @@ -12837,6 +14868,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "iconv-lite": "^0.6.3", "sax": "^1.2.4" @@ -12855,6 +14887,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -12863,34 +14896,13 @@ } }, "node_modules/negotiator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.1.0.tgz", - "integrity": "sha512-NMPBRMJgiQHjbd8phG3Vebdx4kZ1H121rbl5IkMqeOsahptB9BKo/d7oJ3zTXqTgagn2bWlNSXkh0QUGM31RYg==", - "dev": true, - "license": "MIT", - "dependencies": { - "content-type": "^2.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/negotiator/node_modules/content-type": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", - "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", - "dev": true, + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "devOptional": true, "license": "MIT", "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "node": ">= 0.6" } }, "node_modules/neo-async": { @@ -12910,6 +14922,32 @@ "tslib": "^2.0.3" } }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "license": "MIT", + "optional": true + }, + "node_modules/node-exports-info": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.2.tgz", + "integrity": "sha512-kXs9Go0cah0qHVV2v389IXQLdLCeE1xfFtjOAF+iobu0OIoG1pje8At2vMHyaPMiPMnG/LWP50twML21eMcAag==", + "dev": true, + "license": "MIT", + "dependencies": { + "array.prototype.flatmap": "^1.3.3", + "es-errors": "^1.3.0", + "object.entries": "^1.1.9", + "semver": "^6.3.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/node-forge": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.4.0.tgz", @@ -13088,6 +15126,93 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object.entries": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", + "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.hasown": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.4.tgz", + "integrity": "sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/obuf": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", @@ -13208,6 +15333,25 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/own-keys": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.2.tgz", + "integrity": "sha512-19YVAg7T+WTrxggPukVq7DjTv6+PJ867TmhCvBsYwmbFCsZd344rq2Ld1p0wo8f8Qrrhgp82c6FJRqdXWtSEhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "get-intrinsic": "^1.3.0", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/p-cancelable": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz", @@ -13341,7 +15485,8 @@ "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", "dev": true, - "license": "BlueOak-1.0.0" + "license": "BlueOak-1.0.0", + "peer": true }, "node_modules/package-json/node_modules/@sindresorhus/is": { "version": "0.14.0", @@ -13565,6 +15710,7 @@ "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 0.10" } @@ -13682,15 +15828,10 @@ "license": "ISC" }, "node_modules/path-to-regexp": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", - "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", - "dev": true, - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", + "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", + "license": "MIT" }, "node_modules/path-type": { "version": "6.0.0", @@ -13747,7 +15888,7 @@ "version": "4.0.7", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=12" @@ -13811,16 +15952,6 @@ "pixelmatch": "bin/pixelmatch" } }, - "node_modules/pkce-challenge": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", - "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16.20.0" - } - }, "node_modules/pkg-dir": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", @@ -14782,6 +16913,7 @@ ], "license": "MIT", "optional": true, + "peer": true, "dependencies": { "lodash.merge": "^4.6.2", "needle": "^2.5.2", @@ -14795,6 +16927,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "ms": "^2.1.1" } @@ -14806,6 +16939,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -14820,6 +16954,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "debug": "^3.2.6", "iconv-lite": "^0.4.4", @@ -14855,6 +16990,25 @@ "integrity": "sha512-FuEc12/eKqqoRYIGBrUptCBRhobL19PS2U31vMNTfyck1FxPyMfgsXyW4Mav85y/ZN1hop3hOwRlUDok23oYfQ==", "license": "MIT" }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true, + "license": "MIT" + }, "node_modules/property-expr": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz", @@ -14882,6 +17036,16 @@ "node": ">= 0.10" } }, + "node_modules/proxy-addr/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==", + "devOptional": true, + "license": "MIT", + "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", @@ -15023,33 +17187,42 @@ } }, "node_modules/range-parser": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.3.0.tgz", - "integrity": "sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "devOptional": true, "license": "MIT", "engines": { "node": ">= 0.6" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" } }, "node_modules/raw-body": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", - "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", - "dev": true, + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "devOptional": true, "license": "MIT", "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", - "iconv-lite": "~0.7.0", + "iconv-lite": "~0.4.24", "unpipe": "~1.0.0" }, "engines": { - "node": ">= 0.10" + "node": ">= 0.8" + } + }, + "node_modules/raw-body/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==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" } }, "node_modules/rc": { @@ -15083,7 +17256,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", - "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -15131,9 +17303,8 @@ "version": "0.14.2", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", - "dev": true, + "devOptional": true, "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -15192,14 +17363,37 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", "dev": true, - "license": "MIT" - }, - "node_modules/regenerate-unicode-properties": { + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { "version": "10.2.2", "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", @@ -15226,6 +17420,27 @@ "dev": true, "license": "MIT" }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/regexpu-core": { "version": "6.4.0", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", @@ -15520,7 +17735,6 @@ "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.30.0.tgz", "integrity": "sha512-kQvGasUgN+AlWGliFn2POSajRQEsULVYFGTvOZmK06d7vCD+YhZztt70kGk3qaeAXeWYL5eO7zx+rAubBc55eA==", "license": "MIT", - "peer": true, "bin": { "rollup": "dist/bin/rollup" }, @@ -15532,23 +17746,6 @@ "fsevents": "~2.3.2" } }, - "node_modules/router": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", - "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "depd": "^2.0.0", - "is-promise": "^4.0.0", - "parseurl": "^1.3.3", - "path-to-regexp": "^8.0.0" - }, - "engines": { - "node": ">= 18" - } - }, "node_modules/rrweb-cssom": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", @@ -15606,6 +17803,33 @@ "tslib": "^2.1.0" } }, + "node_modules/safe-array-concat": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.4.tgz", + "integrity": "sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "get-intrinsic": "^1.3.0", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-array-concat/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -15627,6 +17851,48 @@ ], "license": "MIT" }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-push-apply/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -15635,20 +17901,23 @@ "license": "MIT" }, "node_modules/sass": { - "version": "1.77.8", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.8.tgz", - "integrity": "sha512-4UHg6prsrycW20fqLGPShtEvo/WyHRVRHwOP4DzkUrObWoWI05QBSfzU71TVB7PFaL104TwNaHpjlWXAZbQiNQ==", + "version": "1.103.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.103.1.tgz", + "integrity": "sha512-9icZURbP51S6S0QGoyaeqk9uB06GNWxsFYWfH5RgpFgqK5FA8tJcM3AdVxrZEVJ7dz+L87nG95gBKf4VuaMHGw==", "license": "MIT", "dependencies": { - "chokidar": ">=3.0.0 <4.0.0", - "immutable": "^4.0.0", + "chokidar": "^5.0.0", + "immutable": "^5.1.5", "source-map-js": ">=0.6.2 <2.0.0" }, "bin": { "sass": "sass.js" }, "engines": { - "node": ">=14.0.0" + "node": ">=20.19.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" } }, "node_modules/sass-loader": { @@ -15692,6 +17961,34 @@ } } }, + "node_modules/sass/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/sass/node_modules/readdirp": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.1.1.tgz", + "integrity": "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", @@ -15874,49 +18171,47 @@ } }, "node_modules/send": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", - "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", - "dev": true, + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "devOptional": true, "license": "MIT", "dependencies": { - "debug": "^4.4.3", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "fresh": "^2.0.0", - "http-errors": "^2.0.1", - "mime-types": "^3.0.2", - "ms": "^2.1.3", - "on-finished": "^2.4.1", - "range-parser": "^1.2.1", - "statuses": "^2.0.2" + "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": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "node": ">= 0.8.0" } }, - "node_modules/send/node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", - "dev": true, + "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==", + "devOptional": true, "license": "MIT", "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "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==", + "devOptional": true, + "license": "MIT" + }, "node_modules/sentence-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-3.0.4.tgz", @@ -15953,6 +18248,7 @@ "resolved": "https://registry.npmjs.org/seroval-plugins/-/seroval-plugins-1.5.6.tgz", "integrity": "sha512-HXuLAX2pu/UByPpaeo/TaMfvMIi+1QqIoPJYCcAtU8QkVNwgR6MPlGuCQTErV1JwraaMbYaWVIBX7mppzGLATQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=10" }, @@ -15983,20 +18279,6 @@ "url": "https://opencollective.com/express" } }, - "node_modules/serve-index/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==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/serve-index/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -16041,16 +18323,6 @@ "devOptional": true, "license": "MIT" }, - "node_modules/serve-index/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==", - "devOptional": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/serve-index/node_modules/statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -16062,23 +18334,19 @@ } }, "node_modules/serve-static": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", - "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", - "dev": true, + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "devOptional": true, "license": "MIT", "dependencies": { - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "parseurl": "^1.3.3", - "send": "^1.2.0" + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" }, "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "node": ">= 0.8.0" } }, "node_modules/set-function-length": { @@ -16099,6 +18367,37 @@ "node": ">= 0.4" } }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -16428,6 +18727,13 @@ "dev": true, "license": "MIT" }, + "node_modules/stackframe": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", + "devOptional": true, + "license": "MIT" + }, "node_modules/statuses": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", @@ -16445,6 +18751,20 @@ "dev": true, "license": "MIT" }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/stream-parser": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/stream-parser/-/stream-parser-0.3.1.tgz", @@ -16452,6 +18772,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "debug": "2" } @@ -16463,6 +18784,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "ms": "2.0.0" } @@ -16473,7 +18795,8 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true, "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/strict-uri-encode": { "version": "1.1.0", @@ -16537,7 +18860,95 @@ "integrity": "sha512-n69H31OnxSGSZyZbgBlvYIXlrMhJQ0dQAX1js1QDhpaUH6zmU3QYlj07bCwCNlPOu3oRXIubGPl2gDGnHsiCqg==", "dev": true }, - "node_modules/strip-ansi": { + "node_modules/string.prototype.matchall": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", + "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.3", + "set-function-name": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.11.tgz", + "integrity": "sha512-PwvK7BU+CMTJGYQCTZb5RWXIML92lftJLhQz1tBzgKiqGxJaMlBAa48POXaNAC2s4y8jr3EFqrkF9+44neS46w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.2", + "es-object-atoms": "^1.1.2", + "has-property-descriptors": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.10.tgz", + "integrity": "sha512-2+3aDAOmPTmuFwjDnmJG2ctEkQKVki7vOSqaxkv42Mowj1V6PnvuwFCRrR5lChUux1TBskPjfkeTOhqczDMxTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", @@ -16563,6 +18974,16 @@ "node": ">=8" } }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/strip-dirs": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", @@ -16727,6 +19148,7 @@ "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -16738,6 +19160,7 @@ "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", @@ -16759,6 +19182,7 @@ "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, "license": "BlueOak-1.0.0", + "peer": true, "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -16775,6 +19199,7 @@ "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "brace-expansion": "^2.0.2" }, @@ -16791,6 +19216,7 @@ "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", "dev": true, "license": "BlueOak-1.0.0", + "peer": true, "engines": { "node": ">=16 || 14 >=14.17" } @@ -16801,6 +19227,7 @@ "integrity": "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==", "dev": true, "license": "BlueOak-1.0.0", + "peer": true, "engines": { "node": ">=11.0.0" } @@ -16811,6 +19238,7 @@ "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", "dev": true, "license": "BSD-3-Clause", + "peer": true, "engines": { "node": ">= 12" } @@ -17189,7 +19617,6 @@ "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -17201,24 +19628,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/terser-webpack-plugin/node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", @@ -17513,6 +19922,76 @@ "node": ">=0.8.0" } }, + "node_modules/ts-api-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", + "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths-webpack-plugin": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-4.2.0.tgz", + "integrity": "sha512-zbem3rfRS8BgeNK50Zz5SIQgXzLafiHjOwUAvk/38/o1jHn/V5QAgVUcz884or7WYcPaH3N2CIfUc2u0ul7UcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.7.0", + "tapable": "^2.2.1", + "tsconfig-paths": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/tsconfig-paths-webpack-plugin/node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -17568,68 +20047,95 @@ } }, "node_modules/type-is": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", - "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", - "dev": true, + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "devOptional": true, "license": "MIT", "dependencies": { - "content-type": "^2.0.0", - "media-typer": "^1.1.0", - "mime-types": "^3.0.0" + "media-typer": "0.3.0", + "mime-types": "~2.1.24" }, "engines": { - "node": ">= 18" + "node": ">= 0.6" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "engines": { + "node": ">= 0.4" } }, - "node_modules/type-is/node_modules/content-type": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", - "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", "dev": true, "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, "engines": { - "node": ">=18" + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/type-is/node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", "dev": true, "license": "MIT", "dependencies": { - "mime-db": "^1.54.0" + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" }, "engines": { - "node": ">=18" + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/typed-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", - "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "node_modules/typed-array-length": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.8.tgz", + "integrity": "sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.14" + "call-bind": "^1.0.9", + "for-each": "^0.3.5", + "gopd": "^1.2.0", + "is-typed-array": "^1.1.15", + "possible-typed-array-names": "^1.1.0", + "reflect.getprototypeof": "^1.0.10" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/typescript": { @@ -17638,7 +20144,6 @@ "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -17667,6 +20172,25 @@ "node": ">=0.8.0" } }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/unbzip2-stream": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", @@ -17760,12 +20284,6 @@ "path-to-regexp": "^6.2.0" } }, - "node_modules/universal-router/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==", - "license": "MIT" - }, "node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", @@ -17954,7 +20472,6 @@ "integrity": "sha512-+v57oAaoYNnO3hIu5Z/tJRZjq5aHM2zDve9YZ8HngVHbhk66RStobhb1sqPMIPEleV6cNKYK4eGrAbE9Ulbl2g==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.18.10", "postcss": "^8.4.27", @@ -18597,7 +21114,6 @@ "integrity": "sha512-rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^1.0.5", @@ -18647,7 +21163,6 @@ "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", "devOptional": true, "license": "MPL-2.0", - "peer": true, "dependencies": { "deepmerge": "^1.5.2", "javascript-stringify": "^2.0.1" @@ -18655,450 +21170,69 @@ "engines": { "node": ">=8" } - }, - "node_modules/webpack-dev-middleware": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", - "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "colorette": "^2.0.10", - "memfs": "^3.4.3", - "mime-types": "^2.1.31", - "range-parser": "^1.2.1", - "schema-utils": "^4.0.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" - } - }, - "node_modules/webpack-dev-middleware/node_modules/ajv": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", - "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", - "devOptional": true, - "license": "MIT", - "peer": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/webpack-dev-middleware/node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/webpack-dev-middleware/node_modules/schema-utils": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", - "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/webpack-dev-server": { - "version": "4.15.2", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz", - "integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==", - "devOptional": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/bonjour": "^3.5.9", - "@types/connect-history-api-fallback": "^1.3.5", - "@types/express": "^4.17.13", - "@types/serve-index": "^1.9.1", - "@types/serve-static": "^1.13.10", - "@types/sockjs": "^0.3.33", - "@types/ws": "^8.5.5", - "ansi-html-community": "^0.0.8", - "bonjour-service": "^1.0.11", - "chokidar": "^3.5.3", - "colorette": "^2.0.10", - "compression": "^1.7.4", - "connect-history-api-fallback": "^2.0.0", - "default-gateway": "^6.0.3", - "express": "^4.17.3", - "graceful-fs": "^4.2.6", - "html-entities": "^2.3.2", - "http-proxy-middleware": "^2.0.3", - "ipaddr.js": "^2.0.1", - "launch-editor": "^2.6.0", - "open": "^8.0.9", - "p-retry": "^4.5.0", - "rimraf": "^3.0.2", - "schema-utils": "^4.0.0", - "selfsigned": "^2.1.1", - "serve-index": "^1.9.1", - "sockjs": "^0.3.24", - "spdy": "^4.0.2", - "webpack-dev-middleware": "^5.3.4", - "ws": "^8.13.0" - }, - "bin": { - "webpack-dev-server": "bin/webpack-dev-server.js" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.37.0 || ^5.0.0" - }, - "peerDependenciesMeta": { - "webpack": { - "optional": true - }, - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-dev-server/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==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/webpack-dev-server/node_modules/ajv": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", - "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", - "devOptional": true, - "license": "MIT", - "peer": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/webpack-dev-server/node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/webpack-dev-server/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/webpack-dev-server/node_modules/body-parser": { - "version": "1.20.6", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.6.tgz", - "integrity": "sha512-p5tAzS57i5MV9fZFDj9LeIiTZEufbSe2eDozP+ElheSUq1m74CRq1jI4mYNDdVs9vQztXFLuk/Gd6BWTdwRJ5g==", - "devOptional": true, - "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/webpack-dev-server/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==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/webpack-dev-server/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/webpack-dev-server/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==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/webpack-dev-server/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==", - "devOptional": true, - "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" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/webpack-dev-server/node_modules/finalhandler": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", - "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", - "devOptional": true, - "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/webpack-dev-server/node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "devOptional": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/webpack-dev-server/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==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack-dev-server/node_modules/ipaddr.js": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.5.0.tgz", - "integrity": "sha512-aq+t5NAc+cS6rZQQVWC2x98CPqGtKKTMDd4Gaodv0wShnItdKg/51djkGJ1hqH+Oy0ivDftCbSLCQob8zso01w==", - "devOptional": true, - "license": "MIT", - "engines": { - "node": ">= 10" - } - }, - "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/webpack-dev-server/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==", - "devOptional": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/webpack-dev-server/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==", - "devOptional": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/webpack-dev-server/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==", + }, + "node_modules/webpack-dev-middleware": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", "devOptional": true, "license": "MIT", + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, "engines": { - "node": ">= 0.6" + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" } }, - "node_modules/webpack-dev-server/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==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/webpack-dev-server/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==", + "node_modules/webpack-dev-middleware/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "devOptional": true, "license": "MIT", - "engines": { - "node": ">= 0.6" + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/webpack-dev-server/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==", + "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", "devOptional": true, "license": "MIT", "dependencies": { - "bytes": "~3.1.2", - "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", - "unpipe": "~1.0.0" + "fast-deep-equal": "^3.1.3" }, - "engines": { - "node": ">= 0.8" + "peerDependencies": { + "ajv": "^8.8.2" } }, - "node_modules/webpack-dev-server/node_modules/schema-utils": { + "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/webpack-dev-middleware/node_modules/schema-utils": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", @@ -19118,59 +21252,121 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/webpack-dev-server/node_modules/send": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", - "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "node_modules/webpack-dev-server": { + "version": "4.15.2", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz", + "integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==", "devOptional": true, "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" + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.5", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.4", + "ws": "^8.13.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } } }, - "node_modules/webpack-dev-server/node_modules/serve-static": { - "version": "1.16.3", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", - "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "node_modules/webpack-dev-server/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "devOptional": true, "license": "MIT", "dependencies": { - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "~0.19.1" + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" }, - "engines": { - "node": ">= 0.8.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/webpack-dev-server/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==", + "node_modules/webpack-dev-server/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", "devOptional": true, "license": "MIT", "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/webpack-dev-server/node_modules/schema-utils": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" }, "engines": { - "node": ">= 0.6" + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, "node_modules/webpack-format-messages": { @@ -19383,6 +21579,80 @@ "node": ">= 8" } }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/which-typed-array": { "version": "1.1.22", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.22.tgz", @@ -19673,27 +21943,6 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } - }, - "node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", - "dev": true, - "license": "MIT", - "peer": true, - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/zod-to-json-schema": { - "version": "3.25.2", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", - "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", - "dev": true, - "license": "ISC", - "peerDependencies": { - "zod": "^3.25.28 || ^4" - } } } } diff --git a/miniProgram/package.json b/miniProgram/package.json index 5cf431c..596f8ca 100644 --- a/miniProgram/package.json +++ b/miniProgram/package.json @@ -1,27 +1,31 @@ { - "name": "biterstore-taro-client", - "version": "0.2.0", + "name": "@biterstore/taro-client", + "version": "0.1.0", "private": true, - "description": "BITerStore Taro dual-platform client for WeChat Mini Program and H5", + "description": "BITerStore Taro dual-platform demo client", "engines": { - "node": ">=22.13.0 <25" + "node": "22.13.x" }, "scripts": { "dev:weapp": "taro build --type weapp --watch", "dev:h5": "taro build --type h5 --watch", "build:weapp": "taro build --type weapp", + "build:weapp:e2e": "set \"BITERSTORE_E2E=1\" && taro build --type weapp", "build:h5": "taro build --type h5", - "lint": "tsc --noEmit", + "qa:h5:visual": "node scripts/h5-visual.mjs", + "lint": "eslint src scripts test --ext .js,.mjs,.ts,.tsx", "test": "vitest run", - "weapp:doctor": "node scripts/weapp-doctor.cjs", - "weapp:open": "node scripts/weapp-open.cjs", - "e2e:weapp:connect": "node scripts/weapp-smoke.cjs --connect", - "e2e:weapp:launch": "node scripts/weapp-smoke.cjs --launch", - "qa:weapp": "npm run build:weapp && npm run e2e:weapp:launch", + "weapp:doctor": "node scripts/weapp-doctor.mjs", + "weapp:open": "node scripts/weapp-open.mjs", + "e2e:weapp:connect": "node scripts/weapp-e2e.mjs --connect", + "e2e:weapp:launch": "node scripts/weapp-e2e.mjs --launch", + "qa:weapp": "npm run build:weapp:e2e && npm run e2e:weapp:launch", "qa:all": "npm run lint && npm test && npm run build:h5 && npm run qa:weapp" }, "dependencies": { + "@babel/runtime": "7.28.4", "@tarojs/components": "4.2.1", + "@tarojs/helper": "4.2.1", "@tarojs/plugin-framework-react": "4.2.1", "@tarojs/plugin-platform-h5": "4.2.1", "@tarojs/plugin-platform-weapp": "4.2.1", @@ -29,25 +33,35 @@ "@tarojs/runtime": "4.2.1", "@tarojs/shared": "4.2.1", "@tarojs/taro": "4.2.1", + "lucide-react": "1.34.0", "react": "18.3.1", "react-dom": "18.3.1" }, "devDependencies": { "@babel/core": "7.29.7", - "@babel/preset-react": "7.28.5", + "@babel/plugin-transform-class-properties": "7.25.9", + "@babel/preset-react": "7.27.1", + "@pmmmwh/react-refresh-webpack-plugin": "0.5.17", "@tarojs/cli": "4.2.1", + "@tarojs/taro-loader": "4.2.1", "@tarojs/webpack5-runner": "4.2.1", - "@types/node": "22.19.19", + "@types/node": "22.18.6", "@types/react": "18.3.24", - "@types/react-dom": "18.3.7", + "@types/webpack-env": "1.18.8", "babel-preset-taro": "4.2.1", "dotenv": "17.4.2", + "eslint": "8.57.1", + "eslint-config-taro": "4.2.1", + "eslint-plugin-react": "7.34.1", + "eslint-plugin-react-hooks": "4.4.0", "miniprogram-automator": "0.12.1", - "miniprogram-automator-mcp": "0.1.1", "react-refresh": "0.14.2", - "sass": "1.77.8", + "tsconfig-paths-webpack-plugin": "4.2.0", "typescript": "5.4.5", - "vite": "4.5.14", - "vitest": "0.34.6" - } + "vitest": "0.34.6", + "webpack": "5.91.0" + }, + "browserslist": [ + "defaults and fully supports es6-module" + ] } diff --git a/miniProgram/project.config.json b/miniProgram/project.config.json index f38938a..16a6bf2 100644 --- a/miniProgram/project.config.json +++ b/miniProgram/project.config.json @@ -1,42 +1,15 @@ { - "appid": "touristappid", - "compileType": "miniprogram", - "projectname": "BITerStore", "miniprogramRoot": "dist/", - "srcMiniprogramRoot": "dist/", - "libVersion": "trial", - "packOptions": { - "ignore": [], - "include": [] - }, + "projectname": "BITerStore Taro", + "description": "BITerStore", + "appid": "touristappid", "setting": { - "coverView": true, + "urlCheck": true, "es6": true, - "postcss": true, - "minified": true, "enhance": true, - "showShadowRootInWxmlPanel": true, - "packNpmRelationList": [], - "babelSetting": { - "ignore": [], - "disablePlugins": [], - "outputPath": "" - }, - "uglifyFileName": false, - "uploadWithSourceMap": true, - "packNpmManually": false, - "minifyWXSS": true, - "localPlugins": false, - "condition": false, - "compileWorklet": false, - "disableUseStrict": false, - "minifyWXML": true, - "useCompilerPlugins": false - }, - "condition": {}, - "editorSetting": { - "tabIndent": "auto", - "tabSize": 2 + "compileHotReLoad": true, + "postcss": true, + "minified": false }, - "simulatorPluginLibVersion": {} + "compileType": "miniprogram" } diff --git a/miniProgram/scripts/h5-visual.mjs b/miniProgram/scripts/h5-visual.mjs new file mode 100644 index 0000000..5cce816 --- /dev/null +++ b/miniProgram/scripts/h5-visual.mjs @@ -0,0 +1,107 @@ +import fs from 'node:fs/promises' +import path from 'node:path' +import { spawn } from 'node:child_process' +import { root } from './weapp-env.mjs' + +const preview = process.env.BITERSTORE_H5_URL || 'http://127.0.0.1:4173' +const chrome = process.env.CHROME_PATH || 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe' +const artifactDir = process.env.BITERSTORE_H5_ARTIFACT_DIR || path.join(root, 'qa-artifacts', 'h5-actual') +const profileDir = path.join(root, 'qa-artifacts', `chrome-cdp-profile-${process.pid}`) +const targets = [ + ['welcome-390', 390, 900, '/'], + ['onboarding-390', 390, 900, '/onboarding'], + ['home-360', 360, 900, '/home'], + ['search-390', 390, 900, '/search'], + ['publish-430', 430, 900, '/publish'], + ['messages-390', 390, 900, '/messages'], + ['notification-390', 390, 900, '/messages/notifications/comment'], + ['chat-390', 390, 900, '/messages/thread-lin'], + ['detail-390', 390, 900, '/books/math-7'], + ['favorites-390', 390, 900, '/favorites'], + ['my-listings-390', 390, 900, '/my-listings'], + ['states-390', 390, 900, '/states'], + ['unavailable-390', 390, 900, '/states/unavailable'], + ['home-820', 820, 1000, '/home'], + ['profile-1280', 1280, 900, '/profile'] +] + +const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)) +async function waitForEndpoint(url) { + for (let attempt = 0; attempt < 30; attempt += 1) { + try { const response = await fetch(url); if (response.ok) return response } catch { /* Chrome is starting */ } + await delay(100) + } + throw new Error(`Chrome debugging endpoint unavailable: ${url}`) +} + +class CdpClient { + constructor(url, onEvent = () => undefined) { + this.nextId = 1 + this.pending = new Map() + this.events = new Map() + this.socket = new WebSocket(url) + this.ready = new Promise((resolve, reject) => { this.socket.onopen = resolve; this.socket.onerror = reject }) + this.socket.onmessage = ({ data }) => { + const message = JSON.parse(data) + if (message.id) { + const pending = this.pending.get(message.id) + if (!pending) return + this.pending.delete(message.id) + return message.error ? pending.reject(new Error(message.error.message)) : pending.resolve(message.result) + } + onEvent(message) + const listeners = this.events.get(message.method) || [] + this.events.delete(message.method) + listeners.forEach((resolve) => resolve(message.params)) + } + } + async send(method, params = {}) { + await this.ready + const id = this.nextId++ + return new Promise((resolve, reject) => { this.pending.set(id, { resolve, reject }); this.socket.send(JSON.stringify({ id, method, params })) }) + } + once(method) { return new Promise((resolve) => this.events.set(method, [...(this.events.get(method) || []), resolve])) } + close() { this.socket.close() } +} + +await fs.mkdir(artifactDir, { recursive: true }) +await fs.mkdir(profileDir, { recursive: true }) +const browser = spawn(chrome, ['--headless=new', '--no-first-run', '--no-sandbox', '--disable-gpu', '--disable-gpu-sandbox', '--use-angle=swiftshader', '--hide-scrollbars', '--remote-allow-origins=*', '--remote-debugging-port=9333', `--user-data-dir=${profileDir}`, 'about:blank'], { windowsHide: true, stdio: 'ignore' }) +let client +const diagnostics = [] +const pages = [] +try { + await waitForEndpoint('http://127.0.0.1:9333/json/version') + const tabResponse = await fetch(`http://127.0.0.1:9333/json/new?${encodeURIComponent(`${preview}/`)}`, { method: 'PUT' }) + const tab = await tabResponse.json() + client = new CdpClient(tab.webSocketDebuggerUrl, (message) => { + if (message.method === 'Runtime.exceptionThrown') diagnostics.push({ type: 'exception', text: message.params.exceptionDetails?.text || 'Runtime exception' }) + if (message.method === 'Runtime.consoleAPICalled' && ['error', 'warning'].includes(message.params.type)) diagnostics.push({ type: message.params.type, text: message.params.args?.map((arg) => arg.value || arg.description).join(' ') }) + }) + await client.send('Page.enable') + await client.send('Runtime.enable') + await client.send('Storage.clearDataForOrigin', { origin: preview, storageTypes: 'all' }) + for (const [name, width, height, route] of targets) { + await client.send('Emulation.setDeviceMetricsOverride', { width, height, deviceScaleFactor: 1, mobile: width < 700 }) + const loaded = client.once('Page.loadEventFired') + await client.send('Page.navigate', { url: `${preview}${route}` }) + await loaded + await delay(750) + await client.send('Runtime.evaluate', { expression: `window.scrollTo(0, 0); document.querySelectorAll('.taro_router, .taro_page, .content-scroll').forEach((element) => { element.scrollTop = 0 })` }) + await delay(100) + if (name === 'welcome-390') { + await client.send('Runtime.evaluate', { expression: `document.querySelector('#e2e-modal-close')?.click()` }) + await delay(250) + } + const pageState = await client.send('Runtime.evaluate', { expression: `(() => { const shell = document.querySelector('.phone-shell'); const selectors = ['.page-title','.primary-button','.welcome-title','.profile-badges','.hero-card','.search-box','.category-chips .chip','.quick-filters > *','.listing-card','.detail-gallery','.detail-gallery .book-cover','.state-grid taro-button-core','.state-grid taro-image-core','.inline-state taro-image-core','.full-state .state-image','.chat-composer']; const measure = element => { const box = element.getBoundingClientRect(); const style = getComputedStyle(element); const child = element.querySelector(':scope > img'); const childBox = child?.getBoundingClientRect(); return { x: Math.round(box.x), y: Math.round(box.y), width: Math.round(box.width), height: Math.round(box.height), fontSize: style.fontSize, lineHeight: style.lineHeight, padding: style.padding, overflow: style.overflow, objectFit: style.objectFit, transform: style.transform, child: childBox ? { x: Math.round(childBox.x), y: Math.round(childBox.y), width: Math.round(childBox.width), height: Math.round(childBox.height), objectFit: getComputedStyle(child).objectFit, transform: getComputedStyle(child).transform } : null }; }; const metrics = Object.fromEntries(selectors.map(selector => [selector, document.querySelector(selector) ? measure(document.querySelector(selector)) : null])); return { url: location.href, text: document.body.innerText, html: document.body.innerHTML.slice(0, 500), metrics, shell: shell ? { className: shell.className, display: getComputedStyle(shell).display, visibility: getComputedStyle(shell).visibility, text: shell.innerText.slice(0, 160) } : null } })()`, returnByValue: true }) + pages.push({ name, url: pageState.result.value.url, textLength: pageState.result.value.text.length, shellClass: pageState.result.value.shell?.className || null, metrics: pageState.result.value.metrics }) + if (!pageState.result.value.shell || pageState.result.value.text.trim().length === 0) diagnostics.push({ type: 'blank-page', text: `${name}: ${pageState.result.value.url}` }) + const result = await client.send('Page.captureScreenshot', { format: 'png', fromSurface: true }) + await fs.writeFile(path.join(artifactDir, `${name}.png`), Buffer.from(result.data, 'base64')) + } + console.log(JSON.stringify({ ok: diagnostics.length === 0, artifactDir, viewports: targets.map(([, width, height]) => `${width}x${height}`), pages, diagnostics })) + if (diagnostics.length) process.exitCode = 1 +} finally { + client?.close() + browser.kill() +} diff --git a/miniProgram/scripts/serve-dist.mjs b/miniProgram/scripts/serve-dist.mjs new file mode 100644 index 0000000..521aa81 --- /dev/null +++ b/miniProgram/scripts/serve-dist.mjs @@ -0,0 +1,26 @@ +import fs from 'node:fs' +import http from 'node:http' +import path from 'node:path' +import { root } from './weapp-env.mjs' + +const dist = path.join(root, 'dist') +const mime = { '.html': 'text/html; charset=utf-8', '.js': 'text/javascript; charset=utf-8', '.css': 'text/css; charset=utf-8', '.webp': 'image/webp' } +http.createServer((request, response) => { + const urlPath = decodeURIComponent((request.url || '/').split('?')[0]) + let file = path.join(dist, urlPath === '/' ? 'index.html' : urlPath) + if (!file.startsWith(dist)) { response.statusCode = 403; response.end(); return } + if (!fs.existsSync(file) || fs.statSync(file).isDirectory()) file = path.join(dist, 'index.html') + if (!fs.existsSync(file)) { + response.statusCode = 503 + response.setHeader('Content-Type', 'text/plain; charset=utf-8') + response.end('H5 build is not ready') + return + } + response.setHeader('Content-Type', mime[path.extname(file)] || 'application/octet-stream') + const stream = fs.createReadStream(file) + stream.on('error', () => { + if (!response.headersSent) response.statusCode = 503 + response.end() + }) + stream.pipe(response) +}).listen(4173, '127.0.0.1', () => console.log('H5 preview http://127.0.0.1:4173')) diff --git a/miniProgram/scripts/weapp-doctor.mjs b/miniProgram/scripts/weapp-doctor.mjs new file mode 100644 index 0000000..a6fc08b --- /dev/null +++ b/miniProgram/scripts/weapp-doctor.mjs @@ -0,0 +1,15 @@ +import fs from 'node:fs' +import net from 'node:net' +import path from 'node:path' +import { spawnSync } from 'node:child_process' +import { assertLocalPaths, automationPort, cliPath, projectPath, root, servicePort, windowsCliInvocation } from './weapp-env.mjs' + +const checks = []; const add = (name, ok, detail, blocking = true) => checks.push({ name, ok, detail, blocking }) +try { assertLocalPaths(); add('paths', true, `${cliPath} | ${projectPath}`) } catch (error) { add('paths', false, error.message) } +add('node', process.versions.node.startsWith('22.13.'), process.versions.node); add('service-port', servicePort > 0, servicePort ? String(servicePort) : '未配置 WECHAT_DEVTOOLS_SERVICE_PORT') +const project = JSON.parse(fs.readFileSync(path.join(root, 'project.config.json'), 'utf8')); add('public-appid', project.appid === 'touristappid', project.appid) +const privatePath = path.join(root, 'project.private.config.json'); add('private-appid', fs.existsSync(privatePath), fs.existsSync(privatePath) ? '本机覆盖存在' : '真机验收前需创建', false) +const loginArgs = ['islogin', '--project', projectPath, ...(servicePort ? ['--port', String(servicePort)] : []), '--lang', 'zh']; const invocation = process.platform === 'win32' ? windowsCliInvocation(loginArgs) : { command: cliPath, args: loginArgs }; const login = spawnSync(invocation.command, invocation.args, { encoding: 'utf8', windowsHide: true, windowsVerbatimArguments: process.platform === 'win32' }); const loginOutput = [login.stdout, login.stderr, login.error?.message].filter(Boolean).join('\n').trim(); add('devtools-login', login.status === 0 && /true|已登录|login/i.test(loginOutput), loginOutput.slice(-500) || `CLI 退出码 ${login.status}`) +const portFree = await new Promise((resolve) => { const server = net.createServer(); server.once('error', () => resolve(false)); server.listen(automationPort, '127.0.0.1', () => server.close(() => resolve(true))) }); add('automation-port', true, portFree ? `${automationPort} 可用于 launch` : `${automationPort} 已占用,可用于 connect`, false) +add('build-output', fs.existsSync(path.join(root, 'dist', 'app.json')), fs.existsSync(path.join(root, 'dist', 'app.json')) ? 'WeApp 构建存在' : '先运行 npm run build:weapp') +const result = { ok: !checks.some((x) => !x.ok && x.blocking), checks }; console.log(JSON.stringify(result, null, 2)); if (!result.ok) process.exitCode = 1 diff --git a/miniProgram/scripts/weapp-e2e.mjs b/miniProgram/scripts/weapp-e2e.mjs new file mode 100644 index 0000000..8e70d9e --- /dev/null +++ b/miniProgram/scripts/weapp-e2e.mjs @@ -0,0 +1,27 @@ +import fs from 'node:fs' +import path from 'node:path' +import automator from 'miniprogram-automator' +import { assertLocalPaths, automationPort, cliPath, projectPath, root, wsEndpoint } from './weapp-env.mjs' + +const mode = process.argv.includes('--connect') ? 'connect' : 'launch' +const artifactRoot = path.join(root, 'qa-artifacts', new Date().toISOString().replace(/[:.]/g, '-')) +fs.mkdirSync(artifactRoot, { recursive: true }) +const consoleEvents = []; const exceptions = []; let app +const namespace = 'biterstore:taro:v1' +const write = (name, value) => fs.writeFileSync(path.join(artifactRoot, name), typeof value === 'string' ? value : JSON.stringify(value, null, 2)) +async function required(page, selector) { const element = await page.$(selector); if (!element) throw new Error(`缺少稳定元素 ${selector} @ ${page.path}`); return element } +async function shot(name) { await app.screenshot({ path: path.join(artifactRoot, `${name}.png`) }) } +async function stored(key) { const result = await app.callWxMethod('getStorage', { key: `${namespace}:${key}` }); return result?.data } +async function scenario(name, run) { try { await app.callWxMethod('clearStorage'); consoleEvents.length = 0; exceptions.length = 0; await run(); const consoleErrors = consoleEvents.filter((event) => event?.type === 'error'); if (exceptions.length || consoleErrors.length) throw new Error(`检测到 ${exceptions.length} 个异常和 ${consoleErrors.length} 个 console error`); await shot(`${name}-passed`); return { name, ok: true } } catch (error) { const page = await app.currentPage().catch(() => null); await shot(`${name}-failed`).catch(() => undefined); write(`${name}-failure.json`, { route: page?.path, error: error.stack || error.message, consoleEvents, exceptions, structure: page ? await page.wxml().catch(() => '') : '' }); return { name, ok: false, error: error.message } } } +try { + assertLocalPaths(); app = mode === 'connect' ? await automator.connect({ wsEndpoint }) : await automator.launch({ cliPath, projectPath, port: automationPort, timeout: 60000 }) + app.on('console', (event) => consoleEvents.push(event)); app.on('exception', (event) => exceptions.push(event)) + const results = [] + results.push(await scenario('onboarding-home', async () => { await app.reLaunch('/pages/welcome/index'); let page = await app.currentPage(); await page.waitFor(150); const close = await page.$('#e2e-modal-close'); if (close) await close.tap(); await (await required(page, '#e2e-welcome-start')).tap(); for (let i = 0; i < 3; i += 1) { page = await app.currentPage(); await (await required(page, '#e2e-onboarding-next')).tap() } page = await app.currentPage(); if (page.path !== 'pages/home/index') throw new Error(`首页路由错误: ${page.path}`); await required(page, '#e2e-home-search-entry'); if (!await stored('onboarding')) throw new Error('引导完成状态未持久化') })) + results.push(await scenario('search-detail-favorite-contact', async () => { await app.switchTab('/pages/search/index'); let page = await app.currentPage(); await (await required(page, '#e2e-search-input')).input('高等数学'); await page.waitFor(300); await (await required(page, '#e2e-listing-math-7')).tap(); page = await app.currentPage(); await (await required(page, '#e2e-detail-favorite')).tap(); if (!(await stored('favorites'))?.includes('math-7')) throw new Error('收藏未写入 Repository 存储'); await (await required(page, '#e2e-detail-contact')).tap(); page = await app.currentPage(); if (page.path !== 'pages/chat/index') throw new Error(`联系卖家未进入聊天: ${page.path}`) })) + results.push(await scenario('publish-fixture-draft-success', async () => { await app.switchTab('/pages/publish/index'); let page = await app.currentPage(); await (await required(page, '#e2e-publish-media')).tap(); await (await required(page, '#e2e-publish-title')).input('自动化测试教材'); await (await required(page, '#e2e-publish-price')).input('16'); await (await required(page, '#e2e-publish-tobby-ai')).tap(); await (await required(page, '#e2e-publish-save')).tap(); if ((await stored('draft'))?.title !== '自动化测试教材') throw new Error('草稿未持久化'); await (await required(page, '#e2e-publish-submit')).tap(); page = await app.currentPage(); await required(page, '#e2e-state-success'); if (!(await stored('listings'))?.some((item) => item.title === '自动化测试教材')) throw new Error('发布结果未写入 Repository 存储') })) + results.push(await scenario('messages-notification-text-image', async () => { await app.switchTab('/pages/messages/index'); let page = await app.currentPage(); await (await required(page, '#e2e-notification-n1')).tap(); page = await app.currentPage(); await required(page, '#e2e-notification-detail-comment'); await app.navigateBack(); page = await app.currentPage(); await (await required(page, '#e2e-thread-thread-lin')).tap(); page = await app.currentPage(); await (await required(page, '#e2e-message-input')).input('你好,还在吗?'); await (await required(page, '#e2e-message-send')).tap(); await (await required(page, '#e2e-message-image')).tap(); const thread = (await stored('threads'))?.find((item) => item.id === 'thread-lin'); if (!thread?.messages.some((item) => item.text === '你好,还在吗?') || !thread.messages.some((item) => item.kind === 'image')) throw new Error('文字或 fixture 图片消息未持久化') })) + results.push(await scenario('favorites-profile-replay-reset', async () => { await app.switchTab('/pages/search/index'); let page = await app.currentPage(); await page.waitFor(200); await (await required(page, '#e2e-listing-math-7')).tap(); page = await app.currentPage(); await (await required(page, '#e2e-detail-favorite')).tap(); await app.navigateTo('/pages/favorites/index'); page = await app.currentPage(); await required(page, '#e2e-listing-math-7'); await app.switchTab('/pages/profile/index'); page = await app.currentPage(); await required(page, '#e2e-profile-reset'); await app.navigateTo('/pages/my-listings/index'); page = await app.currentPage(); await required(page, '#e2e-my-listings-empty'); await app.reLaunch('/pages/onboarding/index'); page = await app.currentPage(); await required(page, '#e2e-onboarding-next') })) + results.push(await scenario('all-states', async () => { for (const state of ['loading', 'searching', 'empty', 'no-results', 'network', 'maintenance', 'unavailable', 'success', 'not-found']) { await app.reLaunch(`/pages/states/index?type=${state}`); const page = await app.currentPage(); await required(page, `#e2e-state-${state}`) } })) + write('result.json', { mode, results }); const ok = results.every((x) => x.ok); console.log(JSON.stringify({ ok, artifactRoot, results }, null, 2)); if (!ok) process.exitCode = 1 +} catch (error) { write('launch-failure.json', { error: error.stack || error.message }); console.error(JSON.stringify({ ok: false, artifactRoot, error: error.message }, null, 2)); process.exitCode = 1 } finally { if (app) { if (mode === 'launch') await app.close().catch(() => undefined); else await app.disconnect().catch(() => undefined) } } diff --git a/miniProgram/scripts/weapp-env.mjs b/miniProgram/scripts/weapp-env.mjs new file mode 100644 index 0000000..06ebc60 --- /dev/null +++ b/miniProgram/scripts/weapp-env.mjs @@ -0,0 +1,15 @@ +import fs from 'node:fs' +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import dotenv from 'dotenv' + +export const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..') +dotenv.config({ path: path.join(root, '.env.weapp.local'), quiet: true }) +export const cliPath = process.env.WECHAT_DEVTOOLS_CLI || 'D:\\Program Files (x86)\\Tencent\\微信web开发者工具\\cli.bat' +export const projectPath = process.env.WEAPP_PROJECT_PATH || root +export const servicePort = Number(process.env.WECHAT_DEVTOOLS_SERVICE_PORT || 0) +export const automationPort = Number(process.env.WEAPP_AUTOMATION_PORT || 9420) +export const wsEndpoint = `ws://127.0.0.1:${automationPort}` +export function commandArgs(command) { const args = [command, '--project', projectPath, '--auto-port', String(automationPort), '--trust-project']; if (servicePort) args.push('--port', String(servicePort)); if (process.env.WECHAT_DEVTOOLS_CLI_TOKEN) args.push('--token', process.env.WECHAT_DEVTOOLS_CLI_TOKEN); args.push('--lang', 'zh'); return args } +export function windowsCliInvocation(args) { const quote = (value) => `"${String(value).replaceAll('"', '""')}"`; const commandLine = [cliPath, ...args].map(quote).join(' '); return { command: process.env.ComSpec || 'cmd.exe', args: ['/d', '/s', '/c', `"${commandLine}"`] } } +export function assertLocalPaths() { if (!fs.existsSync(cliPath)) throw new Error(`微信 CLI 不存在: ${cliPath}`); if (!fs.existsSync(path.join(projectPath, 'project.config.json'))) throw new Error(`微信项目配置不存在: ${projectPath}`) } diff --git a/miniProgram/scripts/weapp-open.mjs b/miniProgram/scripts/weapp-open.mjs new file mode 100644 index 0000000..c7778a5 --- /dev/null +++ b/miniProgram/scripts/weapp-open.mjs @@ -0,0 +1,4 @@ +import { spawn } from 'node:child_process' +import { assertLocalPaths, cliPath, commandArgs, windowsCliInvocation } from './weapp-env.mjs' + +assertLocalPaths(); const args = commandArgs('auto'); const invocation = process.platform === 'win32' ? windowsCliInvocation(args) : { command: cliPath, args }; const child = spawn(invocation.command, invocation.args, { detached: true, stdio: 'ignore', windowsHide: true, windowsVerbatimArguments: process.platform === 'win32' }); child.unref(); console.log(JSON.stringify({ ok: true, pid: child.pid, message: '微信开发者工具自动化通道启动中' })) diff --git a/miniProgram/src/app.config.ts b/miniProgram/src/app.config.ts index fb7c854..401356c 100644 --- a/miniProgram/src/app.config.ts +++ b/miniProgram/src/app.config.ts @@ -1,38 +1,21 @@ export default defineAppConfig({ + entryPagePath: 'pages/welcome/index', pages: [ - 'pages/welcome/index', - 'pages/onboarding/index', - 'pages/home/index', - 'pages/search/index', - 'pages/book-detail/index', - 'pages/publish/index', - 'pages/messages/index', - 'pages/notification-detail/index', - 'pages/chat/index', - 'pages/profile/index', - 'pages/favorites/index', - 'pages/my-listings/index', - 'pages/states/index', - 'pages/not-found/index', + 'pages/welcome/index', 'pages/onboarding/index', 'pages/home/index', + 'pages/search/index', 'pages/publish/index', 'pages/messages/index', + 'pages/profile/index', 'pages/listing/detail', 'pages/notification/detail', + 'pages/chat/index', 'pages/favorites/index', 'pages/my-listings/index', + 'pages/states/index' ], - window: { - navigationStyle: 'custom', - backgroundColor: '#F7F4EA', - backgroundTextStyle: 'dark', - }, + window: { navigationStyle: 'custom', backgroundColor: '#f7f4ea', backgroundTextStyle: 'dark' }, tabBar: { - custom: true, - color: '#77766E', - selectedColor: '#4F5940', - backgroundColor: '#FFFDF8', - borderStyle: 'white', + custom: true, color: '#7f846f', selectedColor: '#4f5940', backgroundColor: '#fffdf7', list: [ { pagePath: 'pages/home/index', text: '首页' }, - { pagePath: 'pages/search/index', text: '搜索' }, + { pagePath: 'pages/search/index', text: '分类' }, { pagePath: 'pages/publish/index', text: '发布' }, { pagePath: 'pages/messages/index', text: '消息' }, - { pagePath: 'pages/profile/index', text: '我的' }, - ], - }, - lazyCodeLoading: 'requiredComponents', + { pagePath: 'pages/profile/index', text: '我的' } + ] + } }) diff --git a/miniProgram/src/app.css b/miniProgram/src/app.css new file mode 100644 index 0000000..f76d20f --- /dev/null +++ b/miniProgram/src/app.css @@ -0,0 +1,221 @@ +/* Taro compatibility only. Visual values live in golden.css, copied verbatim + * from web/app/globals.css so the original H5 remains the single design source. */ +:root, page { + --sage: #6f7956; --olive: #4f5940; --soft-sage: #aeb69a; --cream: #f7f4ea; + --paper: #fffdf8; --border: #d5c7a7; --text: #303229; --muted: #77766e; + --price: #c56e3b; --gold: #c8ae72; --aqua: #78d8c6; + --shadow: 0 14px 34px rgba(76,73,54,.11); + color: var(--text); background: #deddd6; + font-family: "Noto Sans SC", "Microsoft YaHei", system-ui, sans-serif; +} +page, #app { min-height: 100%; } +#app { min-height: 100dvh; display: grid; place-items: start center; background: radial-gradient(circle at 20% 0%,rgba(174,182,154,.45),transparent 32rem),linear-gradient(135deg,#e8e5dc,#cbcfc3); } +button, input, textarea { font: inherit; } +button { width: auto; min-width: 0; min-height: 0; margin: 0; padding: 0; border: 0; border-radius: 0; background: transparent; line-height: normal; } +button::after { border: 0; } +taro-text-core, taro-button-core { font-size: inherit; line-height: inherit; } +taro-image-core { display: block; } +taro-image-core > img { width: 100%; height: 100%; left: 0 !important; top: 0 !important; transform: none !important; } + +/* Taro renders View/Text/Image as custom elements on H5 and native nodes on + * WeChat. These aliases preserve the original element-based selectors. */ +.brand-mark .brand-leaf { width: 15px; height: 24px; background: var(--olive); border-radius: 3px 8px 3px 4px; transform: skewY(9deg); box-shadow: inset -2px 0 rgba(255,255,255,.3); } +.brand-mark .brand-leaf + .brand-leaf { transform: scaleX(-1) skewY(9deg); } +.page-topbar .brand-label { display: inline; } +.page-title { margin: 0; color: var(--text); font: 700 20px/1.2 "Noto Serif SC","Songti SC",serif; white-space: nowrap; } +.phone-shell { font-size: 16px; line-height: normal; } +.header-icon, .leaf-action, .round-button { font-size: 24px; line-height: 1; } +.search-box > .glyph:first-child, .search-input > .glyph:first-child { font-size: 20px; } +.notice-icon { font-size: 22px; } +.detail-title > button { font-size: 24px; } +.primary-button, .secondary-button { font-size: 16px; line-height: 1; } +.avatar-image { width: 100%; height: 100%; object-fit: cover; } +.avatar-image > img { width: 100%; height: 100%; object-fit: cover; } +.image-avatar .avatar-image { width: 126%; height: 126%; object-fit: contain; transform: translate(-10%,7%); } +.image-avatar .avatar-image > img { object-fit: contain; } +.avatar-initial { font-size: 14px; } +.hero-title { display: block; margin: 0; color: var(--olive); font: 700 27px/1.28 "Noto Serif SC","Songti SC",serif; letter-spacing: .03em; white-space: pre-line; } +.hero-description { display: block; margin: 9px 0 15px; color: #6e7365; font-size: 13.5px; line-height: 1.6; } +.home-page .search-box { width: fit-content; max-width: 100%; } +.category-chips .chip { height: 40px; min-height: 40px; display: inline-flex; align-items: center; margin: 0; padding-top: 0; padding-bottom: 0; } +.search-placeholder { color: #8b887e; font-size: 16px; } +.search-box > .glyph:last-child { margin-left: auto; font-size: 18px; } +.section-more { display: inline-flex; align-items: center; gap: 2px; border: 0; background: transparent; color: #8a877c; font-size: 12px; } +.section-heading-text { display: block; color: var(--olive); font: 700 18px/1.2 "Noto Serif SC","Songti SC",serif; } +.section-heading-text::before { content: '❧'; margin-right: 7px; color: var(--sage); } +.section-note { color: #8a877c; font-size: 12px; } +.tile-title { min-height: 38px; display: block; margin: 9px 1px 1px; font-size: 14px; font-weight: 700; line-height: 1.45; } +.tile-author { display: block; margin: 0; overflow: hidden; color: var(--muted); font-size: 12px; text-overflow: ellipsis; white-space: nowrap; } +.book-meta .book-price { color: var(--price); font: 700 15px Georgia,serif; } +.book-meta .book-campus { padding: 3px 6px; border-radius: 6px; background: #eef0e2; color: #687159; font-size: 11px; } +.cover-title { position: relative; z-index: 1; font: 700 15px/1.35 "Noto Serif SC",serif; } +.cover-caption { margin-top: 9px; font-size: 7px; letter-spacing: .08em; opacity: .75; } +.book-cover.cream, .book-cover.paper { background: linear-gradient(145deg,#f3eee0,#c8ceb7); } +.book-cover.warm { color: #504038; background: linear-gradient(145deg,#e7c9b8,#f3e4d8); } +.book-cover.mint { background: linear-gradient(145deg,#bad0bc,#e5eee0); } +.book-cover.night, .book-cover.ink { color: #eef0e5; background: linear-gradient(145deg,#596252,#9aa28a); } +.book-cover.sand { background: linear-gradient(145deg,#d8c59d,#f1e6ce); } +.book-cover.clay { color: #f8eee7; background: linear-gradient(145deg,#9b6655,#d7a78d); } +.book-cover.earth { color: #f0eee5; background: linear-gradient(145deg,#655f50,#a49b82); } +.listing-heading .listing-title { min-width: 0; flex: 1; display: block; font-size: 14px; font-weight: 700; line-height: 1.45; } +.more-glyph { flex: 0 0 auto; width: 20px; font-size: 18px; } +.listing-author { display: block; margin: 4px 0 9px; overflow: hidden; color: var(--muted); font-size: 11px; text-overflow: ellipsis; white-space: nowrap; } +.listing-price .price-current { color: var(--olive); font: 700 20px Georgia,serif; } +.listing-price .price-original { color: #aaa69b; font-size: 9px; text-decoration: line-through; } +.listing-price .condition { margin-left: auto; padding: 4px 7px; border: 1px solid #d7cfb2; border-radius: 8px; color: #697357; font-size: 9px; } +.seller-avatar { width: 25px; height: 25px; border: 2px solid var(--paper); border-radius: 50%; object-fit: cover; box-shadow: 0 0 0 1px var(--border); } +.status-badge, .status-tag { position: absolute; z-index: 2; left: 5px; right: auto; top: 5px; width: auto; padding: 5px 8px; border-radius: 8px; background: rgba(93,110,75,.92); color: white; font-size: 9px; } +.status-badge.sold, .status-badge.offline, .status-tag.sold, .status-tag.offline { background: rgba(112,108,99,.88); } +.rank-copy, .rank-price { min-width: 0; } +.rank-copy text, .rank-price text { display: block; } +.rank-copy text:first-child { overflow: hidden; font-size: 12px; font-weight: 700; text-overflow: ellipsis; white-space: nowrap; } +.rank-copy text:nth-child(2) { margin-top: 3px; overflow: hidden; color: var(--muted); font-size: 9px; text-overflow: ellipsis; white-space: nowrap; } +.rank-copy text:last-child { margin-top: 5px; color: #7c826e; font-size: 9px; } +.rank-price { text-align: right; } +.rank-price text:first-child { color: var(--price); font: 700 13px Georgia,serif; } +.rank-price text:last-child { margin-top: 5px; color: #8b8c80; font-size: 8px; } + +.welcome-greeting { display: inline-flex; align-items: center; gap: 5px; padding: 8px 14px; border: 1px solid var(--border); border-radius: 18px; background: rgba(255,253,248,.76); color: #656a59; font-size: 12px; } +.welcome-title { display: block; margin: 13px 0 10px; color: #4e5248; font: 700 36px/1.25 "Noto Serif SC","Songti SC",serif; white-space: pre-line; } +.welcome-accent { color: var(--sage); } +.welcome-description { display: block; margin: 0; color: var(--muted); font-size: 13px; line-height: 1.85; white-space: pre-line; } +.welcome-page .welcome-tobby { width: 68%; height: 265px; object-fit: contain; } +.welcome-steps .step-number { color: #a89b7b; font: 700 10px Georgia,serif; } +.welcome-step { min-width: 0; display: flex; flex-direction: column; align-items: center; text-align: center; position: relative; } +.welcome-step:not(:last-child)::after { content: '→'; position: absolute; right: -7px; top: 12px; color: #c9bc9c; } +.welcome-step > .glyph { width: 25px; height: 25px; margin: 6px 0; color: var(--sage); font-size: 22px; } +.welcome-steps .step-title { font: 700 14px "Noto Serif SC",serif; } +.welcome-steps .step-copy { margin-top: 3px; color: var(--muted); font-size: 8px; white-space: nowrap; } +.welcome-footnote { margin: 7px 0 0; text-align: center; color: #8f8c80; font-size: 10px; } +.welcome-actions .primary-button, .welcome-actions .secondary-button { min-height: 48px; font-size: 16px; line-height: 1; } +.onboarding-tobby { width: 80%; height: 340px; flex: 0 1 340px; min-height: 0; margin: auto auto -17px; object-fit: contain; filter: drop-shadow(0 20px 18px rgba(0,0,0,.2)); } +.onboarding-tobby > img { object-fit: contain; } +.onboarding-heading > text { font: 700 24px "Noto Serif SC",serif; } +.onboarding-heading > button { min-height: 42px; padding: 0 15px; font-size: 14px; } +.guide-step { color: var(--gold); font: 700 10px Georgia,serif; letter-spacing: .16em; } +.guide-title { display: block; margin: 7px 0; color: var(--olive); font: 700 24px "Noto Serif SC",serif; } +.guide-copy { display: block; margin: 0; color: var(--muted); font-size: 12px; line-height: 1.7; } +.guide-pills > text { display: flex; align-items: center; gap: 3px; width: auto; padding: 5px 8px; border-radius: 999px; background: #eef0e2; color: #677056; font-size: 9px; line-height: 1; } +.guide-pills .glyph { font-size: 12px; } +.step-dots > text { width: 7px; height: 7px; border-radius: 50%; background: rgba(255,255,255,.45); } +.step-dots > text.active { width: 22px; border-radius: 8px; background: white; } +.search-tobby-hint .search-hint-image { width: 65px; height: 58px; object-fit: contain; filter: drop-shadow(0 5px 5px rgba(69,71,53,.1)); } +.search-hint-copy { position: relative; max-width: 205px; padding: 8px 11px; border: 1px solid rgba(213,199,167,.78); border-radius: 14px 14px 14px 5px; background: rgba(255,253,248,.9); color: #74766a; font-size: 10.5px; line-height: 1.5; box-shadow: 0 5px 14px rgba(82,78,59,.05); } +.search-hint-copy text { display: block; } +.search-hint-copy text:first-child { color: var(--olive); font-size: 11.5px; font-weight: 700; } +.results-heading > text:first-child { font: 700 17px "Noto Serif SC",serif; } +.results-heading > text:first-child text { color: var(--price); } +.results-heading > text:last-child { color: var(--muted); font-size: 9px; } +.detail-heading { display: block; margin: 7px 0 3px; font: 700 21px/1.35 "Noto Serif SC",serif; } +.detail-author { display: block; margin: 0; color: var(--muted); font-size: 12px; } +.detail-current-price { color: var(--price); font: 700 27px Georgia,serif; } +.detail-original-price { color: #a6a195; font-size: 12px; text-decoration: line-through; } +.detail-condition { margin-left: auto; padding: 5px 8px; border: 1px solid #d8cfb5; border-radius: 8px; color: #657054; font-size: 10.5px; } +.detail-facts > text { display: flex; align-items: center; gap: 5px; color: #6d7065; font-size: 10.5px; } +.detail-facts > text:last-child { grid-column: 1 / -1; } +.description-title { display: block; margin: 0; font: 700 15px "Noto Serif SC",serif; } +.description-copy { display: block; margin: 1em 0; color: #62645c; font-size: 12px; line-height: 1.8; } +.description-block view > text { padding: 5px 8px; border-radius: 999px; background: #f0eee3; color: #707364; font-size: 10.5px; } +.seller-name { display: block; font-size: 14px; font-weight: 700; } +.seller-campus { display: block; margin: 4px 0; color: var(--muted); font-size: 10.5px; } +.seller-response { display: block; color: #79806b; font-size: 10px; } +.stepper-item { position: relative; display: flex; flex-direction: column; align-items: center; color: #aaa69c; } +.stepper-number { width: 28px; height: 28px; display: grid; place-items: center; border: 1px solid #d9cfb9; border-radius: 50%; background: #fffdf8; font: 700 11px Georgia,serif; } +.stepper .stepper-label { width: auto; height: auto; margin: 5px 0 0; padding: 0; border: 0; border-radius: 0; background: transparent; font: 400 10px/1.2 "Noto Sans SC","Microsoft YaHei",sans-serif; } +.stepper .stepper-line { position: absolute; width: calc(100% - 38px); height: 1px; left: calc(50% + 19px); top: 14px; padding: 0; border: 0; border-radius: 0; background: #d9cfb9; } +.stepper-item.active { color: var(--olive); } +.stepper-item.active .stepper-number { border-color: var(--sage); background: var(--sage); color: white; box-shadow: 0 4px 10px rgba(79,89,64,.18),inset 0 0 0 2px rgba(255,255,255,.2); } +.add-image .glyph { font-size: 25px; } +.add-image-title { display: block; margin-top: 7px; font-size: 11px; font-weight: 700; } +.add-image-copy { display: block; margin-top: 3px; color: var(--muted); font-size: 8px; } +.tobby-tip image { width: 94px; height: 94px; object-fit: contain; } +.tobby-tip > text { padding: 8px 11px; border: 1px solid var(--border); border-radius: 14px; background: #fffdf8; color: #6d705f; font-size: 9px; } +.ai-title { display: block; color: var(--olive); font: 700 13px "Noto Serif SC",serif; } +.ai-copy { display: block; margin-top: 5px; color: var(--muted); font-size: 9px; } +.form-label { display: block; color: #65685e; font-size: 10px; font-weight: 700; } +.form-field input, .form-field textarea, .select-control { width: 100%; margin-top: 6px; padding: 11px; border: 1px solid #ddd2ba; border-radius: 12px; background: #fffefa; color: var(--text); font-size: 12px; } +.form-field textarea { min-height: 105px; } +.notice-title { display: block; font: 700 15px "Noto Serif SC",serif; } +.notice-subtitle { display: block; margin: 5px 0 0; color: var(--muted); font-size: 11px; line-height: 1.45; } +.notice-link { display: block; margin-top: 6px; color: var(--sage); font-size: 10px; font-weight: 700; } +.notice-count { position: absolute; right: 8px; top: 8px; width: 20px; height: 20px; display: grid; place-items: center; border-radius: 50%; background: #e69a4f; color: white; font-size: 9px; } +.message-title { margin: 18px 2px 9px; } +.all-read { display: flex; align-items: center; gap: 3px; color: #838479; font-size: 9px; } +.thread-copy { min-width: 0; text-align: left; } +.thread-name { display: block; font-size: 13px; font-weight: 700; } +.thread-campus { margin-left: 5px; color: #7b806e; font-size: 8px; font-weight: 400; } +.thread-message { display: block; margin-top: 6px; overflow: hidden; color: var(--muted); font-size: 10px; text-overflow: ellipsis; white-space: nowrap; } +.thread-time { align-self: start; color: #9b988e; font-size: 8px; } +.thread-unread { position: absolute; right: 10px; bottom: 10px; width: 20px; height: 20px; display: grid; place-items: center; border-radius: 50%; background: #e5924b; color: white; font-size: 10px; } +.tobby-banner .tobby-banner-image { position: absolute; width: 96px; height: 96px; object-fit: contain; left: -4px; bottom: -3px; } +.tobby-banner-copy { color: #6b6f61; font-size: 10.5px; line-height: 1.6; } +.tobby-banner-copy > text { color: var(--olive); font-weight: 700; } +.profile-name { display: flex; align-items: center; gap: 6px; margin: 0 0 6px; font: 700 20px "Noto Serif SC",serif; } +.profile-badges > text { font-size: 11px; } +.profile-campus { display: block; margin: 7px 0 4px; color: #6e735f; font-size: 11px; } +.profile-bio { display: block; overflow: hidden; color: var(--muted); font-size: 11px; text-overflow: ellipsis; white-space: nowrap; } +.profile-stat-value { color: var(--olive); font: 700 19px Georgia,serif; } +.profile-stat-label { margin-top: 4px; color: var(--muted); font-size: 11px; } +.profile-reminder .profile-reminder-image { width: 86px; height: 86px; object-fit: contain; align-self: end; margin-bottom: -10px; } +.profile-reminder-copy { margin: 0; color: #6f7265; font-size: 11px; line-height: 1.55; } +.profile-reminder-copy > text { color: var(--olive); font-weight: 700; } +.menu-title { display: block; margin: 0 0 7px; color: var(--olive); font: 700 14px "Noto Serif SC",serif; } +.profile-menu .menu-icon { width: 36px; height: 36px; display: grid; place-items: center; border-radius: 11px; background: #eef0e4; color: var(--sage); } +.menu-label, .menu-detail { display: block; } +.menu-label { font-size: 13px; font-weight: 700; } +.menu-detail { margin-top: 4px; color: var(--muted); font-size: 11px; } +.profile-menu button.danger .menu-icon { background: #fff0ec; color: #b75f54; } +.message-content { max-width: 72%; } +.message-bubble { display: block; margin: 0; padding: 10px 12px; border: 1px solid #ded4be; border-radius: 6px 16px 16px 16px; background: rgba(255,253,248,.91); font-size: 11px; line-height: 1.6; } +.message-row.mine .message-bubble { border-color: #cbd1b5; border-radius: 16px 6px 16px 16px; background: #e8ecdc; } +.message-time { display: block; margin-top: 4px; color: #99968d; font-size: 8px; } +.message-row.mine .message-time { text-align: right; } +.shared-title, .shared-author, .shared-price { display: block; } +.shared-title { font-size: 10px; font-weight: 700; } +.shared-author { margin: 5px 0; color: var(--muted); font-size: 8px; } +.shared-price { color: var(--price); font: 700 13px Georgia,serif; } +.inline-state > image, .inline-state > taro-image-core { width: 190px; height: 190px; object-fit: contain; } +.inline-state > taro-image-core > img { object-fit: contain; } +.inline-title { display: block; margin-top: -8px; color: var(--olive); font: 700 16px "Noto Serif SC",serif; } +.inline-copy { display: block; margin: 7px 0 14px; color: var(--muted); font-size: 10px; } +.state-card-title { position: relative; z-index: 1; font: 700 11px "Noto Serif SC",serif; } +.full-state .state-image { position: relative; width: 260px; height: 260px; object-fit: contain; filter: drop-shadow(0 18px 18px rgba(70,72,56,.12)); } +.full-state .state-image > img { object-fit: contain; } +.state-title { position: relative; display: block; margin: -12px 0 8px; color: var(--olive); font: 700 25px "Noto Serif SC",serif; } +.state-copy { position: relative; display: block; max-width: 290px; margin: 0; color: var(--muted); font-size: 12px; line-height: 1.8; } +.state-footnote { position: absolute; bottom: 25px; color: #9b978c; font-size: 8px; } +.notification-kicker { display: block; margin: 0; color: var(--gold); font-size: 9px; font-weight: 700; letter-spacing: .12em; } +.notification-title { display: block; margin: 3px 0 4px; color: var(--olive); font: 700 21px "Noto Serif SC",serif; } +.notification-subtitle { display: block; color: var(--muted); font-size: 12px; } +.notification-unread { align-self: start; position: relative; z-index: 1; padding: 5px 8px; border-radius: 999px; background: var(--sage); color: white; font-size: 9px; } +.feed-source { display: block; font-size: 14px; font-weight: 700; } +.feed-copy { display: block; margin: 5px 0; color: #686b60; font-size: 12px; line-height: 1.6; } +.feed-time { display: block; color: #96948a; font-size: 10px; } + +.glyph { display: inline-flex; align-items: center; justify-content: center; font-family: Georgia,serif; } +.glyph svg { width: 1em; height: 1em; display: block; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; } +.grow { flex: 1; } +.empty { padding: 36px 18px; text-align: center; color: var(--muted); } +.inline-toast { margin-top: 10px; padding: 10px 12px; border: 1px solid var(--border); border-radius: 12px; background: #fffdf8; color: var(--olive); font-size: 12px; } +.modal-mask, .drawer-mask { position: fixed; z-index: 100; inset: 0; display: flex; align-items: flex-end; justify-content: center; background: rgba(40,42,36,.45); } +.modal-card, .filter-drawer { width: min(100%,430px); padding: 22px; border-radius: 24px 24px 0 0; background: var(--paper); box-shadow: 0 -16px 40px rgba(40,42,36,.2); } +.modal-card > button { width: 100%; margin-top: 16px; } +.filter-drawer { max-height: 80vh; overflow-y: auto; } +.sheet-heading { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; } +.menu-row { min-height: 50px; display: flex; align-items: center; border-bottom: 1px dashed #ddd2b9; } + +/* Element-selector equivalents required by Taro H5 custom elements. */ +.hero-tobby > img, .search-hint-image > img, .tobby-banner-image > img, +.profile-reminder-image > img, .state-image > img { object-fit: contain; } +.state-grid taro-image-core { position: absolute; width: 115px; height: 115px; right: -12px; top: -9px; opacity: .88; } +.state-grid taro-image-core > img { object-fit: contain; } +.state-grid .state-card-title { position: relative; z-index: 1; font: 700 12px "Noto Serif SC",serif; } +.detail-gallery > .book-cover { min-width: 100%; height: 275px; flex: 0 0 100%; } +.chat-composer { font-size: 16px; } +.chat-composer .send-button { min-width: 58px; min-height: 42px; padding: 0 13px; border-radius: 13px; background: var(--sage); color: white; font-size: 14px; font-weight: 700; } +.chat-composer taro-input-core { min-width: 0; height: 42px; padding: 0 11px; border: 1px solid #dfd4bd; border-radius: 13px; background: #fbf9f2; font-size: 12px; } +.chat-composer taro-input-core input { height: 100%; font-size: 12px; } + +@media (max-width: 370px) { .hero-title { font-size: 24px; } } +@media (min-width: 700px) { #app { padding: 0; } .taro_page { box-sizing: border-box; padding: 16px; display: grid; place-items: start center; background: radial-gradient(circle at 20% 0%,rgba(174,182,154,.45),transparent 32rem),linear-gradient(135deg,#e8e5dc,#cbcfc3); } .hero-title { font-size: 34px; } .welcome-title { font-size: 44px; } } +@media (min-width: 1024px) { .taro_page { padding: 24px; place-items: center; } .onboarding-tobby { width: 440px; max-height: 44vh; object-fit: contain; } } diff --git a/miniProgram/src/app.scss b/miniProgram/src/app.scss deleted file mode 100644 index 1c2e98d..0000000 --- a/miniProgram/src/app.scss +++ /dev/null @@ -1,168 +0,0 @@ -:root { - --sage: #6f7956; - --olive: #4f5940; - --soft-sage: #aeb69a; - --cream: #f7f4ea; - --paper: #fffdf8; - --border: #d5c7a7; - --text: #303229; - --muted: #77766e; - --price: #c56e3b; - --gold: #c8ae72; - --aqua: #78d8c6; -} - -page, html, body, #app { height: 100%; margin: 0; background: #d9ddd1; color: var(--text); } -page, body, button, input, textarea { font-family: "Noto Sans SC", "Microsoft YaHei", system-ui, sans-serif; } -view, text, image, button, input, textarea, scroll-view { box-sizing: border-box; } -button { margin: 0; padding: 0; color: inherit; line-height: inherit; background: transparent; border: 0; } -button::after { border: 0; } - -.app-stage { width: 100%; min-height: 100vh; display: flex; justify-content: center; background: radial-gradient(circle at 20% 0%, rgba(174,182,154,.52), transparent 44%), linear-gradient(135deg, #e8e5dc, #cdd1c6); } -.phone-shell { position: relative; width: 100%; max-width: 430px; height: 100vh; min-height: 100vh; display: flex; flex-direction: column; overflow: hidden; background: var(--cream); box-shadow: 0 0 58px rgba(47,52,39,.2); } -.paper-texture { position: absolute; inset: 0; pointer-events: none; opacity: .12; background: radial-gradient(circle at 86% 10%, rgba(174,182,154,.34), transparent 24%), radial-gradient(circle at 8% 68%, rgba(213,199,167,.28), transparent 27%); } -.content-scroll { position: relative; z-index: 1; flex: 1; min-height: 0; width: 100%; padding: 6px 18px 118px; } -.content-scroll.no-nav { padding-bottom: 28px; } - -.brand { display: flex; align-items: center; gap: 9px; color: var(--olive); font: 700 25px/1 Georgia, "Noto Serif SC", serif; } -.brand-mark { width: 31px; height: 28px; display: flex; align-items: center; justify-content: center; gap: 1px; color: #eef0dd; font-size: 17px; letter-spacing: -7px; border-radius: 5px 11px 5px 6px; background: linear-gradient(90deg, #657253 49%, transparent 50%, #657253 52%); box-shadow: inset 0 0 0 1px rgba(255,255,255,.25); } -.brand-mark text:last-child { transform: translateX(-2px); } -.topbar { position: relative; z-index: 5; flex: 0 0 auto; min-height: 76px; display: flex; align-items: flex-end; justify-content: space-between; padding: max(15px, env(safe-area-inset-top)) 20px 11px; background: linear-gradient(to bottom, rgba(255,253,248,.98), rgba(255,253,248,.8)); } -.brand-button, .round-button, .icon-button { min-height: 43px; display: flex; align-items: center; justify-content: center; } -.brand-button { overflow: visible; } -.round-button, .icon-button { width: 43px; border: 1px solid rgba(213,199,167,.55); border-radius: 50%; background: rgba(255,253,248,.75); } -.page-topbar { display: grid; grid-template-columns: 1fr auto 1fr; align-items: end; } -.page-topbar .top-actions { justify-content: flex-end; } -.topbar-title { align-self: center; padding-bottom: 11px; color: var(--olive); font: 700 20px/1.2 "Noto Serif SC", serif; white-space: nowrap; } -.top-actions { display: flex; align-items: center; gap: 9px; } -.icon-button { position: relative; font-size: 22px; } -.notification-dot { position: absolute; width: 7px; height: 7px; top: 5px; right: 5px; border: 2px solid var(--paper); border-radius: 50%; background: #df6752; } -.mini-avatar { width: 39px; height: 39px; display: flex; align-items: center; justify-content: center; border: 2px solid var(--paper); border-radius: 50%; color: white; background: linear-gradient(145deg, var(--sage), var(--soft-sage)); box-shadow: 0 0 0 1px var(--border); font: 700 15px Georgia, serif; } -.glyph { display: inline-flex; align-items: center; justify-content: center; min-width: 1em; color: currentColor; font-family: Georgia, "Times New Roman", serif; font-style: normal; } -.glyph-more { font-size: 12px; letter-spacing: 1px; } - -.primary-button, .secondary-button { min-height: 49px; display: flex; align-items: center; justify-content: center; gap: 7px; padding: 0 20px; border-radius: 17px; font-size: 14px; font-weight: 700; } -.primary-button { border: 1px solid #586246; color: white; background: linear-gradient(145deg, #788261, #5f6b4b); box-shadow: 0 9px 20px rgba(79,89,64,.2), inset 0 1px rgba(255,255,255,.25); } -.secondary-button { border: 1px solid var(--border); color: #666b59; background: rgba(255,253,248,.9); } - -.search-box { min-height: 54px; display: flex; align-items: center; gap: 12px; padding: 0 16px; border: 1px solid rgba(181,163,126,.72); border-radius: 18px; color: #85857c; background: rgba(255,253,248,.94); box-shadow: 0 6px 18px rgba(93,81,57,.07); font-size: 14px; } -.search-box text:nth-child(2) { flex: 1; } -.search-box .glyph { color: var(--olive); font-size: 22px; } -.category-chips { width: calc(100% + 18px); margin-right: -18px; padding: 13px 0 12px; white-space: nowrap; } -.chip-row { display: inline-flex; gap: 9px; padding-right: 18px; } -.chip { min-height: 38px; padding: 0 15px; border: 1px solid rgba(213,199,167,.78); border-radius: 999px; color: #5e6057; background: rgba(255,253,248,.78); font-size: 13px; } -.chip.active { color: white; border-color: var(--sage); background: var(--sage); box-shadow: 0 5px 12px rgba(79,89,64,.18); } -.hero-card { position: relative; min-height: 210px; overflow: hidden; border: 1px solid rgba(213,199,167,.86); border-radius: 25px; background: linear-gradient(128deg, #edf0df 0%, #e3e8d5 55%, #cad1b7 100%); box-shadow: 0 14px 34px rgba(76,73,54,.11); } -.hero-card::before { content: ''; position: absolute; inset: 0; background: radial-gradient(circle at 75% 30%, rgba(255,255,255,.9), transparent 32%), repeating-linear-gradient(120deg, transparent 0 24px, rgba(255,255,255,.15) 25px 26px); } -.hero-copy { position: relative; z-index: 2; width: 62%; padding: 22px 0 20px 22px; } -.eyebrow { display: block; margin-bottom: 7px; color: #829071; font-size: 11px; font-weight: 700; letter-spacing: 2px; } -.hero-title { color: var(--olive); font: 700 27px/1.28 "Noto Serif SC", "Songti SC", serif; white-space: pre-line; letter-spacing: 1px; } -.hero-copy > text:not(.eyebrow) { display: block; margin: 9px 0 14px; color: #687060; font-size: 13px; line-height: 1.55; } -.hero-button { width: max-content; min-height: 38px; display: flex; align-items: center; gap: 9px; padding: 0 15px; border-radius: 999px; color: white; background: var(--olive); font-size: 12px; box-shadow: 0 6px 14px rgba(79,89,64,.2); } -.hero-button text { color: #eadba7; } -.hero-tobby { position: absolute; z-index: 1; width: 180px; height: 180px; right: -23px; bottom: -12px; filter: drop-shadow(0 10px 10px rgba(69,71,53,.12)); } -.corner-emblem { position: absolute; top: 15px; right: 17px; color: rgba(79,89,64,.43); font-size: 15px; } -.section-block { margin-top: 22px; } -.section-title { display: flex; align-items: center; justify-content: space-between; margin-bottom: 11px; } -.section-title > view:first-child { color: var(--olive); font: 700 19px/1.2 "Noto Serif SC", serif; } -.section-title > view:first-child::before { content: '❧'; margin-right: 7px; color: var(--sage); } -.section-title > text { color: #89877e; font-size: 12px; } -.section-more { min-height: 36px; display: flex; align-items: center; gap: 3px; padding: 0 11px 0 13px; border: 1px solid rgba(111,121,86,.5); border-radius: 999px; color: var(--olive); background: linear-gradient(145deg, rgba(255,253,248,.95), rgba(235,239,223,.9)); box-shadow: 0 5px 13px rgba(79,89,64,.08); font-size: 12px; font-weight: 700; } -.book-row { width: calc(100% + 18px); margin-right: -18px; white-space: nowrap; } -.book-row-inner { display: inline-flex; gap: 12px; padding: 1px 18px 11px 1px; } -.book-tile { width: 152px; flex: 0 0 152px; padding: 9px; overflow: hidden; border: 1px solid rgba(213,199,167,.65); border-radius: 18px; background: rgba(255,253,248,.9); box-shadow: 0 8px 20px rgba(82,78,59,.07); white-space: normal; } -.book-cover { position: relative; height: 145px; display: flex; flex-direction: column; align-items: center; justify-content: center; overflow: hidden; padding: 14px; border-radius: 10px 14px 14px 9px; color: #35402f; text-align: center; background: linear-gradient(145deg, #aeb99d, #e5e8d8); box-shadow: inset 5px 0 rgba(255,255,255,.25); } -.book-cover::after { content: ''; position: absolute; width: 100px; height: 100px; right: -48px; bottom: -50px; border: 1px solid rgba(255,255,255,.34); border-radius: 50%; } -.book-cover.tone-paper { background: linear-gradient(145deg, #f3eee0, #c8ceb7); } -.book-cover.tone-ink, .book-cover.tone-night { color: #eef0e5; background: linear-gradient(145deg, #596252, #9aa28a); } -.book-cover.tone-mint { background: linear-gradient(145deg, #c9ddcd, #e7eadc); } -.book-cover.tone-sand, .book-cover.tone-clay, .book-cover.tone-earth { background: linear-gradient(145deg, #d8c9aa, #eee6d4); } -.cover-emblem { margin-bottom: 8px; color: var(--olive); font-size: 25px; } -.book-cover-title { position: relative; z-index: 1; display: -webkit-box; overflow: hidden; font: 700 15px/1.36 "Noto Serif SC", serif; white-space: normal; -webkit-box-orient: vertical; -webkit-line-clamp: 3; } -.book-cover-foot { margin-top: 10px; opacity: .73; font-size: 9px; letter-spacing: 1px; } -.book-tile-title { min-height: 41px; margin: 9px 1px 1px; display: -webkit-box; overflow: hidden; font-size: 14px; font-weight: 700; line-height: 1.45; -webkit-box-orient: vertical; -webkit-line-clamp: 2; } -.book-tile-author { display: block; overflow: hidden; color: var(--muted); font-size: 11px; text-overflow: ellipsis; white-space: nowrap; } -.book-meta { display: flex; align-items: center; justify-content: space-between; margin-top: 8px; } -.book-meta text:first-child { color: var(--price); font: 700 17px Georgia, serif; } -.book-meta text:last-child { padding: 4px 7px; border-radius: 7px; color: #687159; background: #eef0e2; font-size: 10px; } -.ranking-card { margin: 14px 0 19px; padding: 14px; border: 1px solid rgba(213,199,167,.7); border-radius: 21px; background: rgba(255,253,248,.86); box-shadow: 0 8px 22px rgba(82,78,59,.06); } -.rank-item { width: 100%; min-height: 86px; display: grid; grid-template-columns: 32px 48px minmax(0,1fr) auto 13px; align-items: center; gap: 8px; padding: 8px 7px 8px 5px; border: 1px solid rgba(213,199,167,.58); border-radius: 15px; background: linear-gradient(100deg, rgba(255,253,248,.92), rgba(244,244,233,.82)); box-shadow: 0 5px 12px rgba(75,75,58,.045); } -.rank-item + .rank-item { margin-top: 8px; } -.rank-number { width: 30px; height: 30px; display: flex; align-items: center; justify-content: center; border: 1px solid rgba(200,174,114,.7); border-radius: 50%; color: #aa8843; background: #fffaf0; font: italic 700 13px Georgia, serif; } -.rank-item .book-cover { width: 48px; height: 64px; padding: 5px; } -.rank-item .cover-emblem { margin: 0 0 3px; font-size: 13px; } -.rank-item .book-cover-title { font-size: 7px; line-height: 1.25; } -.rank-copy { min-width: 0; } -.rank-copy view, .rank-copy text { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } -.rank-copy view { font-size: 13px; font-weight: 700; } -.rank-copy text { margin-top: 4px; color: var(--muted); font-size: 10px; } -.rank-copy text:last-child { color: #7c826e; } -.rank-price { text-align: right; } -.rank-price text { display: block; } -.rank-price text:first-child { color: var(--price); font: 700 15px Georgia, serif; } -.rank-price text:last-child { margin-top: 5px; color: #8b8c80; font-size: 9px; } - -.bottom-nav { position: absolute; z-index: 20; left: 12px; right: 12px; bottom: max(9px, env(safe-area-inset-bottom)); height: 74px; display: grid; grid-template-columns: repeat(5, 1fr); align-items: end; padding: 8px 7px 7px; border: 1px solid rgba(213,199,167,.86); border-radius: 26px; background: rgba(255,253,248,.96); box-shadow: 0 12px 32px rgba(64,67,53,.18); } -.nav-item { min-height: 52px; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; gap: 4px; color: #707268; font-size: 12px; } -.nav-item .glyph { font-size: 24px; line-height: 24px; } -.nav-item.active { color: var(--olive); font-weight: 700; } -.nav-item.publish { position: relative; justify-content: center; color: white; transform: translateY(-9px); } -.nav-item.publish::before { content: ''; position: absolute; z-index: -1; width: 56px; height: 56px; bottom: -2px; border: 5px solid var(--paper); border-radius: 50%; background: var(--sage); box-shadow: 0 0 0 1px var(--border), 0 7px 16px rgba(79,89,64,.23); } -.nav-item.publish view { font-size: 10px; transform: translateY(-2px); } -.weapp-tab-shell { height: 94px; background: transparent; } -.weapp-bottom-nav { position: fixed; } - -.welcome-page { display: block; overflow-y: auto; padding: max(25px, env(safe-area-inset-top)) 24px 30px; background: linear-gradient(rgba(255,253,248,.91), rgba(250,246,234,.94)); } -.welcome-decoration { position: absolute; inset: 0; background: radial-gradient(circle at 90% 26%, rgba(174,182,154,.22), transparent 25%), radial-gradient(circle at 4% 70%, rgba(213,199,167,.22), transparent 22%); } -.welcome-brand { position: relative; z-index: 1; display: flex; align-items: center; justify-content: space-between; } -.leaf-seal { width: 44px; height: 44px; display: flex; align-items: center; justify-content: center; border: 1px solid var(--border); border-radius: 50%; color: var(--sage); background: rgba(255,253,248,.72); font-size: 23px; } -.welcome-copy { position: relative; z-index: 2; margin-top: 34px; } -.hello-pill { width: max-content; padding: 9px 14px; border: 1px solid var(--border); border-radius: 19px; color: #656a59; background: rgba(255,253,248,.78); font-size: 13px; } -.welcome-title { margin: 13px 0 10px; color: #4e5248; font: 700 36px/1.25 "Noto Serif SC", serif; white-space: pre-line; } -.welcome-title text { color: var(--sage); } -.welcome-copy > text { color: var(--muted); font-size: 14px; line-height: 1.85; white-space: pre-line; } -.welcome-tobby { position: relative; z-index: 1; width: 70%; height: 300px; display: block; margin: -41px -27px -48px auto; filter: drop-shadow(0 14px 14px rgba(66,70,52,.12)); } -.welcome-steps { position: relative; z-index: 3; display: grid; grid-template-columns: repeat(3,1fr); gap: 6px; padding: 17px 8px; border: 1px solid rgba(213,199,167,.76); border-radius: 23px; background: rgba(255,253,248,.92); box-shadow: 0 14px 34px rgba(76,73,54,.11); } -.welcome-steps > view { position: relative; display: flex; flex-direction: column; align-items: center; text-align: center; } -.welcome-steps > view:not(:last-child)::after { content: '→'; position: absolute; top: 18px; right: -7px; color: #c9bc9c; } -.welcome-steps text:first-child { color: #a89b7b; font: 700 10px Georgia, serif; } -.welcome-steps .glyph { margin: 7px 0; color: var(--sage); font-size: 25px; } -.welcome-steps view view { font: 700 14px "Noto Serif SC", serif; } -.welcome-steps text:last-child { margin-top: 4px; color: var(--muted); font-size: 9px; } -.welcome-actions { position: relative; z-index: 2; display: grid; gap: 10px; margin-top: 18px; } -.welcome-actions > text { margin-top: 6px; color: #8f8c80; font-size: 11px; text-align: center; } - -.avatar { flex: 0 0 auto; overflow: hidden; display: flex; align-items: center; justify-content: center; border: 2px solid var(--paper); border-radius: 50%; color: white; background: linear-gradient(145deg, #69765c, #a9b697); box-shadow: 0 0 0 1px var(--border); font-weight: 700; } -.avatar image { width: 100%; height: 100%; } -.image-avatar image { width: 122%; height: 122%; transform: translateY(5%); } -.avatar-peach { background: #d9b09d; }.avatar-blue { background: #87a2aa; }.avatar-gold { background: #caa763; }.avatar-olive { background: #66755a; } -.toast { position: fixed; z-index: 100; left: 50%; bottom: 104px; width: min(calc(100% - 52px), 350px); min-height: 47px; display: flex; align-items: center; justify-content: center; gap: 8px; padding: 10px 14px; border: 1px solid var(--border); border-radius: 15px; color: var(--olive); background: rgba(255,253,248,.97); box-shadow: 0 15px 35px rgba(57,61,47,.22); font-size: 13px; transform: translateX(-50%); } -.page-placeholder { min-height: 420px; display: flex; align-items: center; justify-content: center; color: var(--muted); font-size: 14px; } - -.boot-screen { width: 100%; max-width: 430px; min-height: 100vh; display: flex; flex-direction: column; align-items: center; padding: max(28px, env(safe-area-inset-top)) 26px 28px; background: linear-gradient(155deg, rgba(255,253,248,.98), rgba(240,239,225,.98)); } -.boot-brand { width: 100%; display: flex; align-items: center; gap: 8px; color: var(--olive); }.boot-brand > text:last-child { margin-left: auto; color: #8b8b7f; font-size: 11px; }.boot-brand .brand-word { font: 700 25px Georgia,serif; } -.boot-orbit { position: relative; width: 292px; height: 318px; display: flex; align-items: center; justify-content: center; margin: 22px 0 -8px; }.boot-ring { position: absolute; inset: 13px; border: 1px dashed rgba(111,121,86,.38); border-radius: 50%; }.boot-orbit image { z-index: 1; width: 278px; height: 278px; filter: drop-shadow(0 18px 17px rgba(67,70,53,.16)); } -.boot-copy { width: 100%; text-align: center; }.boot-copy > text:first-child { color: var(--gold); font: 700 10px Georgia,serif; letter-spacing: 3px; }.boot-title { margin-top: 8px; color: var(--olive); font: 700 23px/1.48 "Noto Serif SC",serif; }.boot-copy > text:last-child { display: block; margin-top: 9px; color: var(--muted); font-size: 12px; } -.boot-progress { width: 100%; height: 10px; overflow: hidden; margin-top: 25px; border: 1px solid rgba(213,199,167,.8); border-radius: 999px; background: rgba(255,253,248,.72); }.boot-progress view { height: 100%; border-radius: inherit; background: linear-gradient(90deg,var(--sage),var(--aqua),#e3cf96); transition: width .22s ease; }.boot-status { width: 100%; display: flex; justify-content: space-between; margin-top: 8px; color: #74776a; font-size: 11px; }.boot-status text:last-child { color: var(--olive); font-weight: 700; }.boot-foot { margin-top: auto; color: #939185; font-size: 10px; } - -@media (max-width: 370px) { - .content-scroll { padding-left: 14px; padding-right: 14px; } - .topbar { padding-left: 16px; padding-right: 16px; } - .brand { font-size: 22px; } - .hero-title { font-size: 24px; } - .hero-tobby { width: 164px; height: 164px; } - .rank-item { grid-template-columns: 30px 44px minmax(0,1fr) auto 12px; gap: 6px; } - .rank-item .book-cover { width: 44px; height: 60px; } - .rank-price text:last-child { display: none; } -} - -@media (prefers-reduced-motion: no-preference) { - .hero-tobby { animation: float 4s ease-in-out infinite; } - .boot-ring { animation: spin 12s linear infinite; } - .boot-orbit image { animation: float 2.8s ease-in-out infinite; } - .book-tile, .chip, .hero-button, .rank-item, .nav-item { transition: transform .2s ease, box-shadow .2s ease; } - .book-tile:active, .chip:active, .hero-button:active, .rank-item:active { transform: scale(.975); } -} -@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation: none !important; transition: none !important; } } -@keyframes float { 0%,100% { transform: translateY(0) rotate(-1deg); } 50% { transform: translateY(-5px) rotate(1deg); } } -@keyframes spin { to { transform: rotate(360deg); } } diff --git a/miniProgram/src/app.ts b/miniProgram/src/app.ts new file mode 100644 index 0000000..92a8f2c --- /dev/null +++ b/miniProgram/src/app.ts @@ -0,0 +1,8 @@ +import { PropsWithChildren } from 'react' +import './golden.css' +import './h5.css' + +function App({ children }: PropsWithChildren) { + return children +} +export default App diff --git a/miniProgram/src/app.tsx b/miniProgram/src/app.tsx deleted file mode 100644 index 31b50df..0000000 --- a/miniProgram/src/app.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { Image, Text, View } from '@tarojs/components' -import { useEffect, useState } from 'react' -import type { PropsWithChildren } from 'react' - -import { assets, criticalAssets } from './assets' -import { cacheAdapter } from './platform/cache' -import './app.scss' - -function BootScreen({ progress }: { progress: number }) { - return ( - - ◖◗BITerStore移动校园书站 - - - APP RESOURCE PACK - 托比正在准备{process.env.TARO_ENV === 'h5' ? ' App 资源包' : '界面与角色素材'}…… - 第一次见面会稍久一点,之后打开就会快很多。 - - - 正在初始化界面与角色素材{progress}% - 请稍候,书页马上就准备好啦 ❧ - - ) -} - -function App({ children }: PropsWithChildren) { - const [ready, setReady] = useState(false) - const [progress, setProgress] = useState(0) - - useEffect(() => { - let active = true - const started = Date.now() - cacheAdapter.isReady().then(async (cached) => { - if (cached) { - if (active) { setProgress(100); setReady(true) } - return - } - await cacheAdapter.warm(criticalAssets, (value) => active && setProgress(value)) - const remaining = Math.max(0, 700 - (Date.now() - started)) - if (remaining) await new Promise((resolve) => setTimeout(resolve, remaining)) - if (active) { setProgress(100); setReady(true) } - }) - return () => { active = false } - }, []) - - return {ready ? children : } -} - -export default App diff --git a/miniProgram/src/app.weapp.ts b/miniProgram/src/app.weapp.ts new file mode 100644 index 0000000..612a28e --- /dev/null +++ b/miniProgram/src/app.weapp.ts @@ -0,0 +1,13 @@ +import type { PropsWithChildren } from 'react' +import Taro, { useLaunch } from '@tarojs/taro' +import { prepareAssetBundle } from './platform' +import './golden.css' +import './app.css' + +export default function App({ children }: PropsWithChildren) { + useLaunch(() => { + void prepareAssetBundle() + Taro.onPageNotFound(() => { void Taro.redirectTo({ url: '/pages/states/index?type=not-found' }) }) + }) + return children +} diff --git a/miniProgram/src/assets/index.ts b/miniProgram/src/assets/index.ts deleted file mode 100644 index e122c91..0000000 --- a/miniProgram/src/assets/index.ts +++ /dev/null @@ -1,39 +0,0 @@ -import avatarJian from './avatar-jian.webp' -import avatarLin from './avatar-lin.webp' -import avatarZhou from './avatar-zhou.webp' -import paperBg from './paper-bg.webp' -import tobbyCheer from './tobby-cheer.webp' -import tobbyGuidePublish from './tobby-guide-publish.webp' -import tobbyGuideSearch from './tobby-guide-search.webp' -import tobbyGuideTrade from './tobby-guide-trade.webp' -import tobbyHeart from './tobby-heart.webp' -import tobbyHello from './tobby-hello.webp' -import tobbyMaintenance from './tobby-maintenance.webp' -import tobbyMaster from './tobby-master-transparent.webp' -import tobbyNews from './tobby-news.webp' -import tobbyQuestion from './tobby-question.webp' -import tobbySad from './tobby-sad.webp' -import tobbySearch from './tobby-search.webp' -import tobbyUnavailable from './tobby-unavailable.webp' - -export const assets = { - avatarJian, - avatarLin, - avatarZhou, - paperBg, - tobbyCheer, - tobbyGuidePublish, - tobbyGuideSearch, - tobbyGuideTrade, - tobbyHeart, - tobbyHello, - tobbyMaintenance, - tobbyMaster, - tobbyNews, - tobbyQuestion, - tobbySad, - tobbySearch, - tobbyUnavailable, -} as const - -export const criticalAssets = [paperBg, tobbyHello, tobbyMaster, tobbySearch] diff --git a/miniProgram/src/components/AppShell/index.tsx b/miniProgram/src/components/AppShell/index.tsx deleted file mode 100644 index 391ba07..0000000 --- a/miniProgram/src/components/AppShell/index.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { ScrollView, View } from '@tarojs/components' -import type { ViewProps } from '@tarojs/components' -import type { PropsWithChildren } from 'react' - -import { BottomNav } from '../BottomNav' -import type { NavKey } from '../BottomNav' -import { BrandHeader } from '../BrandHeader' - -interface AppShellProps extends PropsWithChildren { - active?: NavKey - title?: string - back?: boolean - noNav?: boolean - className?: string - scrollProps?: Partial -} - -export function AppShell({ children, active, title, back = false, noNav = false, className = '', scrollProps }: AppShellProps) { - const showH5Nav = !noNav && process.env.TARO_ENV === 'h5' - return ( - - - - - {children} - - {showH5Nav && } - - ) -} diff --git a/miniProgram/src/components/BookCard/index.tsx b/miniProgram/src/components/BookCard/index.tsx deleted file mode 100644 index 8b88444..0000000 --- a/miniProgram/src/components/BookCard/index.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import { Button, Text, View } from '@tarojs/components' - -import { formatPrice, listingStatusLabel } from '../../domain/constants' -import { getUser } from '../../domain/demo-data' -import type { Book } from '../../domain/types' -import { navigationAdapter, routes } from '../../platform/navigation' -import { Glyph } from '../Glyph' -import { Avatar } from '../Tobby' - -export function BookCover({ book, compact = false }: { book: Book; compact?: boolean }) { - return ( - - - {book.title} - {!compact && BITerStore 校园藏书} - - ) -} - -export function BookTile({ book }: { book: Book }) { - return ( - navigationAdapter.to(routes.bookDetail, { id: book.id })}> - - {book.title} - {book.author} - ¥{formatPrice(book.price)}{book.condition.slice(0, 2)} - - ) -} - -export function BookListCard({ book, favorite = false, onFavorite, manageAction }: { book: Book; favorite?: boolean; onFavorite?: (book: Book) => void; manageAction?: React.ReactNode }) { - const seller = getUser(book.sellerId) - return ( - - navigationAdapter.to(routes.bookDetail, { id: book.id })}> - - - {book.title} - {book.author} - ¥{formatPrice(book.price)}¥{formatPrice(book.originalPrice)}{book.condition} - {book.campus}校区{book.course} - {seller.name}★ 4.9分 - - - - - - - - {manageAction} - {listingStatusLabel[book.status]} - - ) -} diff --git a/miniProgram/src/components/BottomNav/index.tsx b/miniProgram/src/components/BottomNav/index.tsx deleted file mode 100644 index 57e1164..0000000 --- a/miniProgram/src/components/BottomNav/index.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { View } from '@tarojs/components' - -import { navigationAdapter, routes } from '../../platform/navigation' -import { Glyph } from '../Glyph' -import type { GlyphName } from '../Glyph' - -export type NavKey = 'home' | 'search' | 'publish' | 'messages' | 'profile' - -export const navItems: Array<{ key: NavKey; label: string; route: string; glyph: GlyphName; primary?: boolean }> = [ - { key: 'home', label: '首页', route: routes.home, glyph: 'home' }, - { key: 'search', label: '搜索', route: routes.search, glyph: 'search' }, - { key: 'publish', label: '发布', route: routes.publish, glyph: 'publish', primary: true }, - { key: 'messages', label: '消息', route: routes.messages, glyph: 'message' }, - { key: 'profile', label: '我的', route: routes.profile, glyph: 'user' }, -] - -export function BottomNav({ active }: { active?: NavKey }) { - return ( - - {navItems.map((item) => ( - navigationAdapter.to(item.route)} - key={item.key} - > - {item.label} - - ))} - - ) -} diff --git a/miniProgram/src/components/BrandHeader/index.tsx b/miniProgram/src/components/BrandHeader/index.tsx deleted file mode 100644 index be26935..0000000 --- a/miniProgram/src/components/BrandHeader/index.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { Button, Text, View } from '@tarojs/components' - -import { navigationAdapter, routes } from '../../platform/navigation' -import { Glyph } from '../Glyph' - -export function Brand() { - return BITerStore -} - -export function BrandHeader({ title, back = false }: { title?: string; back?: boolean }) { - return ( - - - {title && {title}} - - - {title ? : } - - - ) -} diff --git a/miniProgram/src/components/FilterDrawer/index.tsx b/miniProgram/src/components/FilterDrawer/index.tsx deleted file mode 100644 index 7c80b1b..0000000 --- a/miniProgram/src/components/FilterDrawer/index.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { Button, Slider, Text, View } from '@tarojs/components' - -import { campuses, categories, conditions, defaultFilters } from '../../domain/constants' -import type { BookFilters } from '../../domain/types' -import { Glyph } from '../Glyph' - -function FilterGroup({ label, options, value, onSelect }: { label: string; options: readonly string[]; value: string; onSelect: (value: string) => void }) { - return {label}{options.map((option) => )} -} - -export function FilterDrawer({ filters, count, onChange, onClose }: { filters: BookFilters; count: number; onChange: (next: BookFilters) => void; onClose: () => void }) { - return ( - - - - - 高级筛选 - 价格区间(元)¥0 — ¥{filters.maxPrice}+ onChange({ ...filters, maxPrice: event.detail.value })} /> - onChange({ ...filters, campus: campus as BookFilters['campus'] })} /> - onChange({ ...filters, category })} /> - onChange({ ...filters, condition: condition as BookFilters['condition'] })} /> - onChange({ ...filters, availableOnly: !filters.availableOnly })}>只看可交易 - - - - ) -} diff --git a/miniProgram/src/components/FormField/index.tsx b/miniProgram/src/components/FormField/index.tsx deleted file mode 100644 index 3806782..0000000 --- a/miniProgram/src/components/FormField/index.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { Text, View } from '@tarojs/components' -import type { PropsWithChildren } from 'react' - -export function FormField({ label, required, error, children }: PropsWithChildren<{ label: string; required?: boolean; error?: string }>) { - return ( - - {required && *}{label} - {children} - {error && {error}} - - ) -} diff --git a/miniProgram/src/components/Glyph.tsx b/miniProgram/src/components/Glyph.tsx new file mode 100644 index 0000000..87bbe1d --- /dev/null +++ b/miniProgram/src/components/Glyph.tsx @@ -0,0 +1,13 @@ +import { Text } from '@tarojs/components' + +export type GlyphName = 'home' | 'search' | 'publish' | 'message' | 'user' | 'bell' | 'back' | 'heart' | 'filter' | 'camera' | 'book' | 'shield' | 'chevron' | 'sparkle' | 'refresh' | 'image' | 'send' | 'check' | 'warning' | 'leaf' | 'more' | 'settings' | 'trade' | 'bookmark' + +const glyphs: Record = { + home: '⌂', search: '⌕', publish: '➤', message: '◌', user: '♙', bell: '♧', back: '‹', + heart: '♡', filter: '≛', camera: '▣', book: '▥', shield: '◈', chevron: '›', sparkle: '✦', + refresh: '↻', image: '▧', send: '➤', check: '✓', warning: '!', leaf: '❧', more: '•••', settings: '⚙', trade: '▣', bookmark: '♡' +} + +export function Glyph({ name, className = '' }: { name: GlyphName; className?: string }) { + return {glyphs[name]} +} diff --git a/miniProgram/src/components/Glyph/index.tsx b/miniProgram/src/components/Glyph/index.tsx deleted file mode 100644 index a71a8cc..0000000 --- a/miniProgram/src/components/Glyph/index.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { Text } from '@tarojs/components' - -export type GlyphName = 'home' | 'search' | 'publish' | 'message' | 'user' | 'bell' | 'back' | 'more' | 'heart' | 'filter' | 'camera' | 'book' | 'pin' | 'shield' | 'chevron' | 'close' | 'sparkle' | 'refresh' | 'image' | 'send' | 'settings' | 'check' | 'warning' - -const glyphs: Record = { - home: '⌂', search: '⌕', publish: '➤', message: '◌', user: '♙', bell: '♧', back: '‹', more: '•••', - heart: '♡', filter: '≛', camera: '▣', book: '▥', pin: '⌖', shield: '◈', chevron: '›', close: '×', - sparkle: '✦', refresh: '↻', image: '▧', send: '➤', settings: '⚙', check: '✓', warning: '!', -} - -export function Glyph({ name, className = '' }: { name: GlyphName; className?: string }) { - return {glyphs[name]} -} diff --git a/miniProgram/src/components/StateView/index.tsx b/miniProgram/src/components/StateView/index.tsx deleted file mode 100644 index f6eb9c1..0000000 --- a/miniProgram/src/components/StateView/index.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { Button, Image, Text, View } from '@tarojs/components' - -import { assets } from '../../assets' -import { navigationAdapter, routes } from '../../platform/navigation' -import { Brand } from '../BrandHeader' - -export type StateType = 'loading' | 'searching' | 'empty' | 'no-results' | 'network' | 'maintenance' | 'unavailable' | 'published' | '404' - -export const stateContent: Record = { - loading: { title: '正在准备页面', text: '托比正在把书页整理好,请稍等一下。', image: assets.tobbySearch, button: '返回首页', target: routes.home }, - searching: { title: '正在搜索好书', text: '书架有点大,托比马上把结果带回来。', image: assets.tobbySearch, button: '返回搜索', target: routes.search }, - empty: { title: '这里还没有内容', text: '第一本书,也许就在等你来发布。', image: assets.tobbyQuestion, button: '发布一本书', target: routes.publish }, - 'no-results': { title: '没有找到相关书籍', text: '试试更短的关键词,或放宽校区和成色筛选。', image: assets.tobbyQuestion, button: '重新搜索', target: routes.search }, - network: { title: '网络好像走丢了', text: '别担心,已填写的内容仍保存在本机。', image: assets.tobbySad, button: '重新加载', target: routes.home }, - maintenance: { title: '托比正在维护书架', text: '系统很快回来,稍后再来看看吧。', image: assets.tobbyMaintenance, button: '返回首页', target: routes.home }, - unavailable: { title: '这本书目前不可用', text: '它可能已经售出或暂时下架,再看看其他好书吧。', image: assets.tobbyUnavailable, button: '发现其他书', target: routes.search }, - published: { title: '发布成功!', text: '你的闲置已经上架,等待下一位同学发现它。', image: assets.tobbyCheer, button: '查看我的发布', target: routes.myListings }, - '404': { title: '好像翻错书页了', text: '这个页面不存在,托比带你回到熟悉的地方。', image: assets.tobbySad, button: '返回首页', target: routes.home }, -} - -export function InlineLoading({ label = '托比正在翻找书架…' }: { label?: string }) { - return {label} -} - -export function InlineEmpty({ onAction }: { onAction?: () => void }) { - return 这次没有找到合适的书换个关键词,或者发布一条求书心愿吧。 -} - -export function FullState({ type }: { type: StateType }) { - const content = stateContent[type] - return {content.title}{content.text}{['loading', 'searching'].includes(type) && }BITerStore · 让每一本书继续被需要 -} diff --git a/miniProgram/src/components/Toast/index.tsx b/miniProgram/src/components/Toast/index.tsx deleted file mode 100644 index 9a43faa..0000000 --- a/miniProgram/src/components/Toast/index.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { Text, View } from '@tarojs/components' -import { useEffect, useState } from 'react' - -export function useToast() { - const [message, setMessage] = useState('') - useEffect(() => { - if (!message) return - const timer = setTimeout(() => setMessage(''), 2200) - return () => clearTimeout(timer) - }, [message]) - return { message, show: setMessage } -} - -export function Toast({ message }: { message: string }) { - if (!message) return null - return {message} -} diff --git a/miniProgram/src/components/Tobby/index.tsx b/miniProgram/src/components/Tobby/index.tsx deleted file mode 100644 index ceeecae..0000000 --- a/miniProgram/src/components/Tobby/index.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { Image, Text, View } from '@tarojs/components' - -import { assets } from '../../assets' -import { CURRENT_USER_ID } from '../../domain/demo-data' -import type { User } from '../../domain/types' - -const avatarMap: Record = { - avatarLin: assets.avatarLin, - avatarZhou: assets.avatarZhou, - avatarJian: assets.avatarJian, -} - -export function Avatar({ user, size = 42 }: { user: User; size?: number }) { - const src = user.id === CURRENT_USER_ID ? assets.tobbyHello : user.avatar ? avatarMap[user.avatar] : undefined - return ( - - {src ? : {user.name.slice(0, 1)}} - - ) -} - -export function TobbyBubble({ image = assets.tobbyHello, title = 'Tobby 提醒', children, compact = false }: { image?: string; title?: string; children: React.ReactNode; compact?: boolean }) { - return ( - - - {title}{children} - - ) -} diff --git a/miniProgram/src/components/ui.tsx b/miniProgram/src/components/ui.tsx new file mode 100644 index 0000000..f297b55 --- /dev/null +++ b/miniProgram/src/components/ui.tsx @@ -0,0 +1,65 @@ +import { PropsWithChildren, ReactNode } from 'react' +import { Button, Image, Input, Text, View } from '@tarojs/components' +import { getUser } from '@/domain/repository' +import { CURRENT_USER_ID } from '@/domain/seed' +import { navigationAdapter } from '@/platform' +import type { Listing, ListingStatus } from '@/domain/types' +import { Glyph } from './Glyph' + +export function Brand() { + return BITerStore +} + +export function BrandHeader({ title, back = false, action }: { title?: string; back?: boolean; action?: ReactNode }) { + const current = getUser(CURRENT_USER_ID) + return + {back ? : } + {title && {title}} + {action || <>{!title && }{title && }} + +} + +export function Avatar({ user, size = 42 }: { user: ReturnType; size?: number }) { + const source = user.id === CURRENT_USER_ID ? '/assets/tobby-hello.webp' : user.avatar + return {source ? : {user.name.slice(0, 1)}} +} + +const h5Tabs: ReadonlyArray = [['home', '首页', 'home'], ['search', '分类', 'grid'], ['publish', '发布', 'send'], ['messages', '消息', 'chat'], ['profile', '我的', 'user']] +function H5Navigation({ active }: { active?: string }) { + if (process.env.TARO_ENV !== 'h5') return null + return {h5Tabs.map(([route, label, icon]) => )} +} + +export function AppShell({ children, title, back, active, className = '', noNav = false }: PropsWithChildren<{ title?: string; back?: boolean; active?: string; className?: string; noNav?: boolean }>) { + const shouldGoBack = back || active === 'publish' + return {children}{!noNav && } +} + +export type TobbyMood = 'hello' | 'search' | 'heart' | 'question' | 'sad' | 'maintenance' | 'cheer' | 'guide-search' | 'guide-publish' | 'guide-trade' | 'unavailable' | 'master' | 'master-transparent' | 'news' +export function Tobby({ mood = 'hello', caption, className = '' }: { mood?: TobbyMood; caption?: string; className?: string }) { return {caption && {caption}} } +export function StatusTag({ status }: { status: ListingStatus }) { const labels: Record = { available: '可交易', sold: '已售', offline: '已下架', draft: '草稿' }; return {labels[status]} } + +export function BookCover({ listing, compact = false }: { listing: Listing; compact?: boolean }) { + return {listing.title}{!compact && BITerStore 校园藏书} +} + +export function BookTile({ listing, onTap }: { listing: Listing; onTap?: () => void }) { + return +} + +export function ListingCard({ listing, onTap, favorite = false, onFavorite, onContact }: { listing: Listing; onTap?: () => void; favorite?: boolean; onFavorite?: () => void; onContact?: () => void }) { + const seller = getUser(listing.sellerId) + return + + {{ available: '可交易', sold: '已售', offline: '已下架', draft: '草稿' }[listing.status]} + +} + +export function RankItem({ listing, index, onTap }: { listing: Listing; index: number; onTap?: () => void }) { + return +} + +export function FormField({ label, value, placeholder, onInput, type = 'text', id }: { label: string; value: string; placeholder?: string; onInput: (value: string) => void; type?: 'text' | 'number'; id?: string }) { return {label} onInput(event.detail.value)} /> } +export function Toast({ children }: PropsWithChildren) { return {children} } +export function Modal({ open, title, children, onClose }: PropsWithChildren<{ open: boolean; title: string; onClose: () => void }>) { if (!open) return null; return event.stopPropagation()}>{title}{children} } +export function FilterDrawer({ open, children, onClose }: PropsWithChildren<{ open: boolean; onClose: () => void }>) { if (!open) return null; return event.stopPropagation()}>{children} } diff --git a/miniProgram/src/custom-tab-bar/index.config.ts b/miniProgram/src/custom-tab-bar/index.config.ts index b1c6ea4..4e68c5a 100644 --- a/miniProgram/src/custom-tab-bar/index.config.ts +++ b/miniProgram/src/custom-tab-bar/index.config.ts @@ -1 +1 @@ -export default {} +export default { component: true } diff --git a/miniProgram/src/custom-tab-bar/index.css b/miniProgram/src/custom-tab-bar/index.css new file mode 100644 index 0000000..f12a2f7 --- /dev/null +++ b/miniProgram/src/custom-tab-bar/index.css @@ -0,0 +1,4 @@ +.custom-tabbar{position:fixed;z-index:30;left:12px;right:12px;bottom:calc(10px + env(safe-area-inset-bottom));height:72px;padding:8px 7px 7px;display:grid;grid-template-columns:repeat(5,1fr);align-items:end;background:rgba(255,253,248,.96);border:1px solid #c8ae72;border-radius:25px;box-shadow:inset 0 0 0 3px rgba(255,255,255,.72),0 12px 32px rgba(64,67,53,.18)} +.custom-tabbar button{position:relative;z-index:1;min-height:51px;margin:0;padding:3px 0 0;line-height:1;background:transparent;color:#707268;font-size:11px;display:flex;flex-direction:column;gap:4px;align-items:center;justify-content:flex-end}.custom-tabbar button::after{display:none}.custom-tabbar button>text:first-child{font-size:21px}.custom-tabbar button.active{color:#4f5940;font-weight:700}.custom-tabbar button.active:not(.publish)::before{content:'';position:absolute;z-index:-1;width:38px;height:38px;top:-2px;border:1px solid rgba(111,121,86,.42);border-radius:50%;background:linear-gradient(145deg,#eef1e3,#dde3ce)}.custom-tabbar button.publish{width:auto;height:auto;justify-self:stretch;margin-top:0;color:white}.custom-tabbar button.publish::before{content:'';position:absolute;z-index:-1;width:54px;height:54px;bottom:-1px;border:5px solid #fffdf8;border-radius:50%;background:#6f7956;box-shadow:0 0 0 1px #d5c7a7,0 7px 16px rgba(79,89,64,.23)}.custom-tabbar button.publish>text:last-child{font-size:9px;transform:translateY(-2px)} +.custom-tabbar .nav-icon{width:20px;height:20px;position:relative;display:block}.custom-tabbar .nav-icon.home{border:2px solid currentColor;border-top:0;border-radius:2px;margin-top:5px}.custom-tabbar .nav-icon.home::before{content:'';position:absolute;width:15px;height:15px;border-left:2px solid currentColor;border-top:2px solid currentColor;transform:rotate(45deg);left:1px;top:-7px}.custom-tabbar .nav-icon.grid{background:radial-gradient(circle,currentColor 0 3px,transparent 3.5px) 0 0/10px 10px}.custom-tabbar .nav-icon.send{width:0;height:0;border-left:19px solid currentColor;border-top:8px solid transparent;border-bottom:8px solid transparent;transform:rotate(-35deg)}.custom-tabbar .nav-icon.chat{border:2px solid currentColor;border-radius:7px}.custom-tabbar .nav-icon.chat::after{content:'';position:absolute;border-top:5px solid currentColor;border-right:5px solid transparent;left:2px;bottom:-5px}.custom-tabbar .nav-icon.user{border:2px solid currentColor;border-radius:50% 50% 42% 42%;height:11px;margin-top:10px}.custom-tabbar .nav-icon.user::before{content:'';position:absolute;width:8px;height:8px;border:2px solid currentColor;border-radius:50%;left:4px;top:-11px;background:#fffdf8} +@media(min-width:1024px){.custom-tabbar{left:max(24px,calc((100vw - 1320px)/2 + 26px));right:auto;top:112px;bottom:48px;width:100px;height:auto;grid-template-columns:1fr;grid-template-rows:repeat(5,1fr)}.custom-tabbar button.publish{margin:0}} diff --git a/miniProgram/src/custom-tab-bar/index.scss b/miniProgram/src/custom-tab-bar/index.scss deleted file mode 100644 index aef0eaa..0000000 --- a/miniProgram/src/custom-tab-bar/index.scss +++ /dev/null @@ -1,4 +0,0 @@ -@import '../app.scss'; - -.weapp-tab-shell { height: 94px; background: transparent; } -.weapp-bottom-nav { position: fixed; } diff --git a/miniProgram/src/custom-tab-bar/index.tsx b/miniProgram/src/custom-tab-bar/index.tsx index 69e046b..9123f09 100644 --- a/miniProgram/src/custom-tab-bar/index.tsx +++ b/miniProgram/src/custom-tab-bar/index.tsx @@ -1,33 +1,7 @@ -import { View } from '@tarojs/components' -import Taro from '@tarojs/taro' -import { useEffect, useState } from 'react' +import Taro, { useDidShow } from '@tarojs/taro' +import { Button, Text, View } from '@tarojs/components' +import { useState } from 'react' +import './index.css' -import { navItems } from '../components/BottomNav' -import { Glyph } from '../components/Glyph' - -export default function CustomTabBar() { - const [active, setActive] = useState(0) - - useEffect(() => { - const route = Taro.getCurrentPages().at(-1)?.route - const index = navItems.findIndex((item) => item.route.slice(1) === route) - if (index >= 0) setActive(index) - }, []) - - return ( - - - {navItems.map((item, index) => ( - Taro.switchTab({ url: item.route })} - key={item.key} - > - {item.label} - - ))} - - - ) -} +const tabs = [['/pages/home/index', 'home', '首页', 'home'], ['/pages/search/index', 'grid', '分类', 'search'], ['/pages/publish/index', 'send', '发布', 'publish'], ['/pages/messages/index', 'chat', '消息', 'messages'], ['/pages/profile/index', 'user', '我的', 'profile']] as const +export default function CustomTabBar() { const [route, setRoute] = useState(''); useDidShow(() => setRoute(`/${Taro.getCurrentInstance().router?.path || ''}`)); return {tabs.map(([url, icon, label, key]) => )} } diff --git a/miniProgram/src/domain/assistant.ts b/miniProgram/src/domain/assistant.ts new file mode 100644 index 0000000..4453574 --- /dev/null +++ b/miniProgram/src/domain/assistant.ts @@ -0,0 +1,14 @@ +import type { ListingAIDraft, PublishDraft } from './types' + +export interface ListingAssistant { generate(input: Partial): Promise } +export const listingAssistant: ListingAssistant = { + async generate(input) { + const course = input.course?.trim() || '课程学习' + const condition = input.condition || '八成新' + return { + title: input.title?.trim() || `${course}教材|${condition}`, + description: `${condition},适合${course}学习与期末复习。支持校内当面验书,有需要可以直接留言。`, + tags: Array.from(new Set([course, condition, '校内自取'])) + } + } +} diff --git a/miniProgram/src/domain/constants.ts b/miniProgram/src/domain/constants.ts deleted file mode 100644 index 881eb37..0000000 --- a/miniProgram/src/domain/constants.ts +++ /dev/null @@ -1,40 +0,0 @@ -import type { BookFilters, PublishDraft } from './types' - -export const categories = ['全部', '教材教辅', '专业课', '考研考公', '文学小说'] as const -export const campuses = ['全部', '中关村', '良乡', '西山', '珠海'] as const -export const conditions = ['全部', '全新', '九成新', '八成新', '七成新及以下'] as const - -export const defaultFilters: BookFilters = { - query: '', - category: '全部', - campus: '全部', - condition: '全部', - minPrice: 0, - maxPrice: 200, - sort: '最新发布', - availableOnly: true, -} - -export const emptyDraft: PublishDraft = { - title: '', - author: '', - isbn: '', - category: '教材教辅', - course: '', - price: '', - originalPrice: '', - condition: '九成新', - campus: '良乡', - description: '', - tags: [], - images: [], -} - -export const formatPrice = (price: number) => price.toFixed(2) - -export const listingStatusLabel = { - available: '可交易', - sold: '已售', - offline: '已下架', - draft: '草稿', -} as const diff --git a/miniProgram/src/domain/filters.ts b/miniProgram/src/domain/filters.ts new file mode 100644 index 0000000..39b331e --- /dev/null +++ b/miniProgram/src/domain/filters.ts @@ -0,0 +1,18 @@ +import type { Listing, ListingFilters } from './types' + +export const defaultFilters: ListingFilters = { query: '', category: '全部', campus: '全部', condition: '全部', minPrice: 0, maxPrice: 200, sort: '最新发布', availableOnly: true } +export function filterListings(listings: Listing[], filters: ListingFilters): Listing[] { + const query = filters.query.trim().toLowerCase() + const result = listings.filter((item) => { + const matches = !query || [item.title, item.author, item.isbn, item.course, ...item.tags].join(' ').toLowerCase().includes(query) + return matches && (filters.category === '全部' || item.category === filters.category) + && (filters.campus === '全部' || item.campus === filters.campus) + && (filters.condition === '全部' || item.condition === filters.condition) + && item.price >= filters.minPrice && item.price <= filters.maxPrice + && (!filters.availableOnly || item.status === 'available') + }) + if (filters.sort === '价格从低到高') result.sort((a, b) => a.price - b.price) + else if (filters.sort === '价格从高到低') result.sort((a, b) => b.price - a.price) + else result.sort((a, b) => b.createdAt.localeCompare(a.createdAt)) + return result +} diff --git a/miniProgram/src/domain/repository.ts b/miniProgram/src/domain/repository.ts new file mode 100644 index 0000000..3b909bf --- /dev/null +++ b/miniProgram/src/domain/repository.ts @@ -0,0 +1,42 @@ +import { mediaAdapter, storageAdapter } from '@/platform' +import { CURRENT_USER_ID, seedListings, seedNotifications, seedThreads, users } from './seed' +import { defaultFilters, filterListings } from './filters' +import type { ChatThread, Listing, ListingFilters, ListingStatus, Message, Notification, PublishDraft, User } from './types' +import { AppError } from './types' + +const KEYS = { listings: 'listings', favorites: 'favorites', threads: 'threads', draft: 'draft', onboarding: 'onboarding', filters: 'filters', notifications: 'notifications', resetNotice: 'reset-notice' } +const wait = (ms = 60) => new Promise((resolve) => setTimeout(resolve, ms)) +export interface DemoRepository { + listListings(filters?: ListingFilters): Promise; getListing(id: string): Promise; + toggleFavorite(id: string): Promise; listFavorites(): Promise; + saveDraft(draft: PublishDraft): Promise; getDraft(): Promise; publishListing(draft: PublishDraft): Promise; + updateListingStatus(id: string, status: ListingStatus): Promise; listMyListings(): Promise; + listThreads(): Promise; getThread(id: string): Promise; sendMessage(threadId: string, text: string, mediaId?: string): Promise; ensureThread(listingId: string): Promise; + listNotifications(): Promise; getProfile(): Promise; isOnboardingComplete(): Promise; completeOnboarding(): Promise; + getFilters(): Promise; saveFilters(filters: ListingFilters): Promise; + shouldShowResetNotice(): Promise; acknowledgeResetNotice(): Promise; resetDemoData(): Promise +} +export const demoRepository: DemoRepository = { + async listListings(filters = defaultFilters) { await wait(); return filterListings(await storageAdapter.get(KEYS.listings, seedListings), filters) }, + async getListing(id) { const item = (await storageAdapter.get(KEYS.listings, seedListings)).find((x) => x.id === id); if (!item) throw new AppError('NOT_FOUND', '商品不存在'); return item }, + async toggleFavorite(id) { const ids = await storageAdapter.get(KEYS.favorites, []); const next = ids.includes(id) ? ids.filter((x) => x !== id) : [...ids, id]; await storageAdapter.set(KEYS.favorites, next); return next.includes(id) }, + async listFavorites() { const ids = await storageAdapter.get(KEYS.favorites, []); return (await storageAdapter.get(KEYS.listings, seedListings)).filter((x) => ids.includes(x.id)) }, + async saveDraft(draft) { await storageAdapter.set(KEYS.draft, draft) }, async getDraft() { return storageAdapter.get(KEYS.draft, null) }, + async publishListing(draft) { + if (!draft.title.trim() || !draft.price || Number(draft.price) <= 0) throw new AppError('VALIDATION', '请填写标题和有效价格') + const item: Listing = { id: `listing-${Date.now()}`, title: draft.title.trim(), author: draft.author.trim(), isbn: draft.isbn.trim(), category: draft.category, course: draft.course.trim(), price: Number(draft.price), originalPrice: Number(draft.originalPrice || draft.price), condition: draft.condition, campus: draft.campus, description: draft.description.trim(), status: 'available', sellerId: CURRENT_USER_ID, createdAt: new Date().toISOString(), tags: draft.tags, tone: 'sage', mediaIds: draft.mediaIds } + await storageAdapter.set(KEYS.listings, [item, ...(await storageAdapter.get(KEYS.listings, seedListings))]); await storageAdapter.remove(KEYS.draft); return item + }, + async updateListingStatus(id, status) { const items = await storageAdapter.get(KEYS.listings, seedListings); await storageAdapter.set(KEYS.listings, items.map((x) => x.id === id ? { ...x, status } : x)) }, + async listMyListings() { return (await storageAdapter.get(KEYS.listings, seedListings)).filter((x) => x.sellerId === CURRENT_USER_ID) }, + async listThreads() { return storageAdapter.get(KEYS.threads, seedThreads) }, + async getThread(id) { const threads = await storageAdapter.get(KEYS.threads, seedThreads); const thread = threads.find((x) => x.id === id); if (!thread) throw new AppError('NOT_FOUND', '会话不存在'); if (thread.unread) { thread.unread = 0; await storageAdapter.set(KEYS.threads, threads) } return thread }, + async sendMessage(threadId, text, mediaId) { const message: Message = { id: `message-${Date.now()}`, senderId: CURRENT_USER_ID, text, createdAt: new Date().toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' }), kind: mediaId ? 'image' : 'text', mediaId }; const threads = (await storageAdapter.get(KEYS.threads, seedThreads)).map((x) => x.id === threadId ? { ...x, updatedAt: message.createdAt, messages: [...x.messages, message] } : x); await storageAdapter.set(KEYS.threads, threads); return message }, + async ensureThread(listingId) { const threads = await storageAdapter.get(KEYS.threads, seedThreads); const existing = threads.find((x) => x.listingId === listingId); if (existing) return existing.id; const listing = await this.getListing(listingId); const thread: ChatThread = { id: `thread-${listingId}`, participantId: listing.sellerId, listingId, unread: 0, updatedAt: '刚刚', messages: [] }; await storageAdapter.set(KEYS.threads, [thread, ...threads]); return thread.id }, + async listNotifications() { return storageAdapter.get(KEYS.notifications, seedNotifications) }, async getProfile() { return users.find((x) => x.id === CURRENT_USER_ID)! }, + async getFilters() { return storageAdapter.get(KEYS.filters, defaultFilters) }, async saveFilters(filters) { await storageAdapter.set(KEYS.filters, filters) }, + async isOnboardingComplete() { return storageAdapter.get(KEYS.onboarding, false) }, async completeOnboarding() { await storageAdapter.set(KEYS.onboarding, true) }, + async shouldShowResetNotice() { return !(await storageAdapter.get(KEYS.resetNotice, false)) }, async acknowledgeResetNotice() { await storageAdapter.set(KEYS.resetNotice, true) }, + async resetDemoData() { const media = await mediaAdapter.list(); await mediaAdapter.remove(media.map((x) => x.id)); await storageAdapter.clearNamespace() } +} +export function getUser(id: string) { return users.find((x) => x.id === id) ?? users[0] } diff --git a/miniProgram/src/domain/demo-data.ts b/miniProgram/src/domain/seed.ts similarity index 60% rename from miniProgram/src/domain/demo-data.ts rename to miniProgram/src/domain/seed.ts index 408dc7b..7f973c9 100644 --- a/miniProgram/src/domain/demo-data.ts +++ b/miniProgram/src/domain/seed.ts @@ -1,63 +1,43 @@ -import type { Book, ChatThread, Notification, NotificationType, User } from './types' +import type { ChatThread, Listing, Notification, User } from './types' export const CURRENT_USER_ID = 'user-tobby' export const users: User[] = [ { id: CURRENT_USER_ID, name: '北理小书童', campus: '良乡', verified: true, bio: '愿每一本书都能遇见新的读者。', responseTime: '通常 10 分钟内回复', avatarTone: 'sage' }, - { id: 'user-lin', name: '林小暖', campus: '中关村', verified: true, bio: '数学与生活都要慢慢理解。', responseTime: '30 分钟内回复', avatarTone: 'peach', avatar: 'avatarLin' }, - { id: 'user-zhou', name: 'Oliver_周', campus: '良乡', verified: true, bio: '计院同学,教材循环利用中。', responseTime: '1 小时内回复', avatarTone: 'blue', avatar: 'avatarZhou' }, - { id: 'user-jian', name: '简一一', campus: '珠海', verified: true, bio: '喜欢文学,也喜欢把书分享出去。', responseTime: '当天回复', avatarTone: 'gold', avatar: 'avatarJian' }, - { id: 'user-leo', name: 'Leo 学长', campus: '西山', verified: true, bio: '毕业清书架,欢迎来问。', responseTime: '15 分钟内回复', avatarTone: 'olive' }, + { id: 'user-lin', name: '林小暖', campus: '中关村', verified: true, bio: '数学与生活都要慢慢理解。', responseTime: '30 分钟内回复', avatarTone: 'peach', avatar: '/assets/avatar-lin.webp' }, + { id: 'user-zhou', name: 'Oliver_周', campus: '良乡', verified: true, bio: '计院同学,教材循环利用中。', responseTime: '1 小时内回复', avatarTone: 'blue', avatar: '/assets/avatar-zhou.webp' }, + { id: 'user-jian', name: '简一一', campus: '珠海', verified: true, bio: '喜欢文学,也喜欢把书分享出去。', responseTime: '当天回复', avatarTone: 'gold', avatar: '/assets/avatar-jian.webp' }, + { id: 'user-leo', name: 'Leo 学长', campus: '西山', verified: true, bio: '毕业清书架,欢迎来问。', responseTime: '15 分钟内回复', avatarTone: 'olive' } ] -export const seedBooks: Book[] = [ - { id: 'math-7', title: '高等数学(第七版)上册', author: '同济大学数学系 编', isbn: '978-7-5608-9493-7', category: '教材教辅', course: '高等数学', price: 28, originalPrice: 49.8, condition: '九成新', campus: '良乡', description: '同济版经典教材,例题讲解清晰,笔记和标注较少,整体干净整洁,适合期末复习备考。', status: 'available', sellerId: 'user-lin', createdAt: '2026-08-24T10:28:00+08:00', tags: ['考研必备', '期末复习', '笔记少'], tone: 'sage' }, - { id: 'data-c', title: '数据结构(C语言版)第2版', author: '严蔚敏 / 清华大学出版社', isbn: '978-7-302-45488-9', category: '专业课', course: '数据结构', price: 25, originalPrice: 49, condition: '八成新', campus: '良乡', description: '计算机专业核心教材,书页完整,有少量重点标注,配合课程使用很方便。', status: 'available', sellerId: 'user-zhou', createdAt: '2026-08-24T09:12:00+08:00', tags: ['计算机', '专业课'], tone: 'paper' }, - { id: 'python', title: 'Python编程:从入门到实践', author: 'Eric Matthes / 人民邮电出版社', isbn: '978-7-115-42802-8', category: '专业课', course: '程序设计', price: 35, originalPrice: 79, condition: '九成新', campus: '中关村', description: '适合零基础学习 Python,案例完整,附带项目实践章节。', status: 'available', sellerId: 'user-leo', createdAt: '2026-08-23T18:40:00+08:00', tags: ['Python', '入门'], tone: 'mint' }, - { id: 'alive', title: '活着', author: '余华', isbn: '978-7-5063-7540-4', category: '文学小说', course: '通识阅读', price: 15, originalPrice: 28, condition: '八成新', campus: '珠海', description: '经典文学作品,书角有轻微使用痕迹,内页无缺损。', status: 'available', sellerId: 'user-jian', createdAt: '2026-08-23T16:00:00+08:00', tags: ['文学', '经典'], tone: 'ink' }, - { id: 'prince', title: '小王子', author: '圣埃克苏佩里', isbn: '978-7-5442-7862-9', category: '文学小说', course: '通识阅读', price: 18, originalPrice: 32, condition: '九成新', campus: '中关村', description: '精装插图版,保存良好,适合收藏或赠送朋友。', status: 'available', sellerId: 'user-lin', createdAt: '2026-08-22T14:10:00+08:00', tags: ['精装', '插图'], tone: 'night' }, - { id: 'linear', title: '线性代数(第六版)', author: '同济大学数学系 编', isbn: '978-7-04-039661-4', category: '教材教辅', course: '线性代数', price: 22, originalPrice: 39.8, condition: '九成新', campus: '西山', description: '只有目录处写过名字,正文干净,适合理工科基础课。', status: 'sold', sellerId: 'user-leo', createdAt: '2026-08-21T11:25:00+08:00', tags: ['数学', '基础课'], tone: 'sand' }, - { id: 'politics', title: '政治学原理', author: '王浦劬', isbn: '978-7-301-23982-1', category: '考研考公', course: '政治学', price: 20, originalPrice: 46, condition: '八成新', campus: '良乡', description: '考研复习使用,有章节索引和少量重点勾画。', status: 'available', sellerId: 'user-zhou', createdAt: '2026-08-20T20:30:00+08:00', tags: ['考研', '社科'], tone: 'clay' }, - { id: 'ordinary-world', title: '平凡的世界(全三册)', author: '路遥', isbn: '978-7-5302-1200-4', category: '文学小说', course: '通识阅读', price: 26, originalPrice: 69, condition: '七成新及以下', campus: '珠海', description: '全三册齐全,封面有使用痕迹,内页完整,不影响阅读。', status: 'offline', sellerId: 'user-jian', createdAt: '2026-08-19T13:00:00+08:00', tags: ['套装', '文学'], tone: 'earth' }, +export const seedListings: Listing[] = [ + { id: 'math-7', title: '高等数学(第七版)上册', author: '同济大学数学系 编', isbn: '978-7-5608-9493-7', category: '教材教辅', course: '高等数学', price: 28, originalPrice: 49.8, condition: '九成新', campus: '良乡', description: '同济版经典教材,例题讲解清晰,笔记和标注较少,整体干净整洁,适合期末复习备考。', status: 'available', sellerId: 'user-lin', createdAt: '2026-08-24T10:28:00+08:00', tags: ['考研必备', '期末复习', '笔记少'], tone: 'sage', mediaIds: [] }, + { id: 'data-c', title: '数据结构(C语言版)第2版', author: '严蔚敏 / 清华大学出版社', isbn: '978-7-302-45488-9', category: '专业课', course: '数据结构', price: 25, originalPrice: 49, condition: '八成新', campus: '良乡', description: '计算机专业核心教材,书页完整,有少量重点标注,配合课程使用很方便。', status: 'available', sellerId: 'user-zhou', createdAt: '2026-08-24T09:12:00+08:00', tags: ['计算机', '专业课'], tone: 'paper', mediaIds: [] }, + { id: 'python', title: 'Python编程:从入门到实践', author: 'Eric Matthes / 人民邮电出版社', isbn: '978-7-115-42802-8', category: '专业课', course: '程序设计', price: 35, originalPrice: 79, condition: '九成新', campus: '中关村', description: '适合零基础学习 Python,案例完整,附带项目实践章节。', status: 'available', sellerId: 'user-leo', createdAt: '2026-08-23T18:40:00+08:00', tags: ['Python', '入门'], tone: 'mint', mediaIds: [] }, + { id: 'alive', title: '活着', author: '余华', isbn: '978-7-5063-7540-4', category: '文学小说', course: '通识阅读', price: 15, originalPrice: 28, condition: '八成新', campus: '珠海', description: '经典文学作品,书角有轻微使用痕迹,内页无缺损。', status: 'available', sellerId: 'user-jian', createdAt: '2026-08-23T16:00:00+08:00', tags: ['文学', '经典'], tone: 'ink', mediaIds: [] }, + { id: 'prince', title: '小王子', author: '圣埃克苏佩里', isbn: '978-7-5442-7862-9', category: '文学小说', course: '通识阅读', price: 18, originalPrice: 32, condition: '九成新', campus: '中关村', description: '精装插图版,保存良好,适合收藏或赠送朋友。', status: 'available', sellerId: 'user-lin', createdAt: '2026-08-22T14:10:00+08:00', tags: ['精装', '插图'], tone: 'night', mediaIds: [] }, + { id: 'linear', title: '线性代数(第六版)', author: '同济大学数学系 编', isbn: '978-7-04-039661-4', category: '教材教辅', course: '线性代数', price: 22, originalPrice: 39.8, condition: '九成新', campus: '西山', description: '只有目录处写过名字,正文干净,适合理工科基础课。', status: 'sold', sellerId: 'user-leo', createdAt: '2026-08-21T11:25:00+08:00', tags: ['数学', '基础课'], tone: 'sand', mediaIds: [] }, + { id: 'politics', title: '政治学原理', author: '王浦劬', isbn: '978-7-301-23982-1', category: '考研考公', course: '政治学', price: 20, originalPrice: 46, condition: '八成新', campus: '良乡', description: '考研复习使用,有章节索引和少量重点勾画。', status: 'available', sellerId: 'user-zhou', createdAt: '2026-08-20T20:30:00+08:00', tags: ['考研', '社科'], tone: 'clay', mediaIds: [] }, + { id: 'ordinary-world', title: '平凡的世界(全三册)', author: '路遥', isbn: '978-7-5302-1200-4', category: '文学小说', course: '通识阅读', price: 26, originalPrice: 69, condition: '七成新及以下', campus: '珠海', description: '全三册齐全,封面有使用痕迹,内页完整,不影响阅读。', status: 'offline', sellerId: 'user-jian', createdAt: '2026-08-19T13:00:00+08:00', tags: ['套装', '文学'], tone: 'earth', mediaIds: [] } ] export const seedThreads: ChatThread[] = [ - { id: 'thread-lin', participantId: 'user-lin', bookId: 'math-7', unread: 2, updatedAt: '10:33', messages: [ - { id: 'm1', senderId: 'user-lin', text: '同学你好,请问《高等数学(第七版)上册》还在吗?', createdAt: '10:28' }, - { id: 'm2', senderId: CURRENT_USER_ID, text: '在的!书还在,可以出~', createdAt: '10:29' }, - { id: 'm3', senderId: 'user-lin', text: '方便拍几张书的实拍图看看吗?', createdAt: '10:30', kind: 'book', bookId: 'math-7' }, - { id: 'm4', senderId: CURRENT_USER_ID, text: '看起来挺新的!价格可以再便宜点吗~', createdAt: '10:32' }, - { id: 'm5', senderId: 'user-lin', text: '原价 49.8,我用得不多,保护得挺好。可以 26 出~', createdAt: '10:32' }, - { id: 'm6', senderId: CURRENT_USER_ID, text: '可以!我们明天下午在三教门口见面吧?', createdAt: '10:33' }, + { id: 'thread-lin', participantId: 'user-lin', listingId: 'math-7', unread: 2, updatedAt: '10:33', messages: [ + { id: 'm1', senderId: 'user-lin', text: '同学你好,请问《高等数学(第七版)上册》还在吗?', createdAt: '10:28', kind: 'text' }, + { id: 'm2', senderId: CURRENT_USER_ID, text: '在的!书还在,可以出~', createdAt: '10:29', kind: 'text' }, + { id: 'm3', senderId: 'user-lin', text: '方便拍几张书的实拍图看看吗?', createdAt: '10:30', kind: 'listing', listingId: 'math-7' }, + { id: 'm4', senderId: CURRENT_USER_ID, text: '看起来挺新的!价格可以再便宜点吗~', createdAt: '10:32', kind: 'text' }, + { id: 'm5', senderId: 'user-lin', text: '原价 49.8,我用得不多,保护得挺好。可以 26 出~', createdAt: '10:32', kind: 'text' }, + { id: 'm6', senderId: CURRENT_USER_ID, text: '可以!我们明天下午在三教门口见面吧?', createdAt: '10:33', kind: 'text' } ] }, - { id: 'thread-zhou', participantId: 'user-zhou', bookId: 'data-c', unread: 1, updatedAt: '昨天 20:15', messages: [{ id: 'z1', senderId: 'user-zhou', text: '发送了 2 张图片,书的边角都拍到了。', createdAt: '20:15', kind: 'image' }] }, - { id: 'thread-jian', participantId: 'user-jian', bookId: 'alive', unread: 0, updatedAt: '昨天 16:42', messages: [{ id: 'j1', senderId: 'user-jian', text: '好的,谢谢!我明天可以自取~', createdAt: '16:42' }] }, - { id: 'thread-leo', participantId: 'user-leo', bookId: 'python', unread: 0, updatedAt: '3天前', messages: [{ id: 'l1', senderId: 'user-leo', text: '没问题,周二下午图书馆门口见~', createdAt: '3天前' }] }, + { id: 'thread-zhou', participantId: 'user-zhou', listingId: 'data-c', unread: 1, updatedAt: '昨天 20:15', messages: [{ id: 'z1', senderId: 'user-zhou', text: '发送了 2 张图片,书的边角都拍到了。', createdAt: '20:15', kind: 'image' }] }, + { id: 'thread-jian', participantId: 'user-jian', listingId: 'alive', unread: 0, updatedAt: '昨天 16:42', messages: [{ id: 'j1', senderId: 'user-jian', text: '好的,谢谢!我明天可以自取~', createdAt: '16:42', kind: 'text' }] }, + { id: 'thread-leo', participantId: 'user-leo', listingId: 'python', unread: 0, updatedAt: '3天前', messages: [{ id: 'l1', senderId: 'user-leo', text: '没问题,周二下午图书馆门口见~', createdAt: '3天前', kind: 'text' }] } ] -export const notifications: Notification[] = [ +export const seedNotifications: Notification[] = [ { id: 'n-like', type: 'like', title: '点赞消息', subtitle: '有人赞了你的内容', unread: 3 }, { id: 'n-comment', type: 'comment', title: '评论消息', subtitle: '有人评论了你的内容', unread: 5 }, { id: 'n-system', type: 'system', title: '系统通知', subtitle: '平台公告与系统通知', unread: 2 }, - { id: 'n-follow', type: 'follow', title: '新增关注', subtitle: '有人关注了你', unread: 1 }, + { id: 'n-follow', type: 'follow', title: '新增关注', subtitle: '有人关注了你', unread: 1 } ] - -export const notificationDetails: Record> = { - like: [ - { source: '林小暖', text: '赞了你发布的《高等数学(第七版)上册》', time: '10:18', target: 'book:math-7' }, - { source: '简一一', text: '赞了你的校园书单「期末复习好书」', time: '昨天 18:42', target: 'favorites' }, - { source: 'Oliver_周', text: '赞了你分享的旧书循环动态', time: '周五 20:06', target: 'profile' }, - ], - comment: [ - { source: 'Oliver_周', text: '评论:书的笔记多吗?方便拍一下目录页吗?', time: '10:05', target: 'book:data-c' }, - { source: '林小暖', text: '评论:这本高数正好是我需要的版本~', time: '昨天 21:30', target: 'book:math-7' }, - { source: 'Leo 学长', text: '评论:中关村校区也可以约时间自取。', time: '昨天 16:12', target: 'chat:thread-leo' }, - ], - system: [ - { source: '校园交易安全提醒', text: '请尽量选择校内公共区域当面交易,确认书况后再付款。', time: '今天 09:00', target: 'state:maintenance' }, - { source: 'BITerStore 试运行公告', text: '演示数据与状态体验入口已经更新完成。', time: '昨天 12:00', target: 'profile' }, - ], - follow: [{ source: '简一一', text: '关注了你,之后发布的新书会更容易被她发现。', time: '昨天 15:26', target: 'chat:thread-jian' }], -} - -export const getUser = (id: string) => users.find((user) => user.id === id) ?? users[0] diff --git a/miniProgram/src/domain/types.ts b/miniProgram/src/domain/types.ts index 957d031..2e13c20 100644 --- a/miniProgram/src/domain/types.ts +++ b/miniProgram/src/domain/types.ts @@ -1,108 +1,27 @@ export type Campus = '中关村' | '良乡' | '西山' | '珠海' export type ListingStatus = 'available' | 'sold' | 'offline' | 'draft' export type Condition = '全新' | '九成新' | '八成新' | '七成新及以下' -export type NotificationType = 'like' | 'comment' | 'system' | 'follow' -export interface User { - id: string - name: string - campus: Campus - verified: boolean - bio: string - responseTime: string - avatar?: string - avatarTone: string +export interface User { id: string; name: string; campus: Campus; verified: boolean; bio: string; responseTime: string; avatar?: string; avatarTone?: 'sage' | 'peach' | 'blue' | 'gold' | 'olive' } +export type Seller = User +export interface StoredMedia { id: string; uri: string; mime: string; size: number; width?: number; height?: number } +export interface Listing { + id: string; title: string; author: string; isbn: string; category: string; course: string; + price: number; originalPrice: number; condition: Condition; campus: Campus; description: string; + status: ListingStatus; sellerId: string; createdAt: string; tags: string[]; tone: string; mediaIds: string[] } - -export interface Seller extends User { - rating: number - completedTrades: number -} - -export interface Book { - id: string - title: string - author: string - isbn: string - category: string - course: string - price: number - originalPrice: number - condition: Condition - campus: Campus - description: string - status: ListingStatus - sellerId: string - createdAt: string - tags: string[] - tone: string - images?: string[] -} - -export interface Listing extends Book { - ownerId: string +export interface ListingFilters { + query: string; category: string; campus: Campus | '全部'; condition: Condition | '全部'; + minPrice: number; maxPrice: number; sort: '最新发布' | '价格从低到高' | '价格从高到低'; availableOnly: boolean } - -export interface BookFilters { - query: string - category: string - campus: Campus | '全部' - condition: Condition | '全部' - minPrice: number - maxPrice: number - sort: '最新发布' | '价格从低到高' | '价格从高到低' - availableOnly: boolean -} - export interface PublishDraft { - title: string - author: string - isbn: string - category: string - course: string - price: string - originalPrice: string - condition: Condition - campus: Campus - description: string - tags: string[] - images: string[] -} - -export interface Message { - id: string - senderId: string - text: string - createdAt: string - kind?: 'text' | 'book' | 'image' - bookId?: string - imagePath?: string -} - -export interface ChatThread { - id: string - participantId: string - bookId: string - unread: number - updatedAt: string - messages: Message[] -} - -export interface Notification { - id: string - type: NotificationType - title: string - subtitle: string - unread: number -} - -export interface ListingAIInput { - imagePaths: string[] - currentDraft: PublishDraft -} - -export type ListingAIDraft = Pick - -export interface ListingAssistant { - generate(input: ListingAIInput): Promise -} + title: string; author: string; isbn: string; category: string; course: string; + price: string; originalPrice: string; condition: Condition; campus: Campus; + description: string; tags: string[]; mediaIds: string[] +} +export interface ListingAIDraft { title: string; description: string; tags: string[] } +export interface Message { id: string; senderId: string; text: string; createdAt: string; kind: 'text' | 'listing' | 'image'; listingId?: string; mediaId?: string } +export interface ChatThread { id: string; participantId: string; listingId: string; unread: number; updatedAt: string; messages: Message[] } +export interface Notification { id: string; type: 'like' | 'comment' | 'system' | 'follow'; title: string; subtitle: string; unread: number } +export type AppErrorCode = 'STORAGE_READ' | 'STORAGE_WRITE' | 'MEDIA_PICK' | 'MEDIA_PERSIST' | 'VALIDATION' | 'NOT_FOUND' +export class AppError extends Error { constructor(public code: AppErrorCode, message: string, public cause?: unknown) { super(message) } } diff --git a/miniProgram/src/golden.css b/miniProgram/src/golden.css new file mode 100644 index 0000000..5de10b6 --- /dev/null +++ b/miniProgram/src/golden.css @@ -0,0 +1,906 @@ +:root { + --sage: #6f7956; + --olive: #4f5940; + --soft-sage: #aeb69a; + --cream: #f7f4ea; + --paper: #fffdf8; + --border: #d5c7a7; + --text: #303229; + --muted: #77766e; + --price: #c56e3b; + --gold: #c8ae72; + --aqua: #78d8c6; + --shadow: 0 14px 34px rgba(76, 73, 54, .11); +} + +* { box-sizing: border-box; } +html, body { margin: 0; min-height: 100%; background: #deddd6; color: var(--text); } +body { font-family: "Noto Sans SC", "Microsoft YaHei", system-ui, sans-serif; } +a { color: inherit; text-decoration: none; } +button, input, textarea, select { font: inherit; } +button { color: inherit; cursor: pointer; } +button, a { -webkit-tap-highlight-color: transparent; } + +.app-stage { + min-height: 100dvh; + display: grid; + place-items: start center; + background: + radial-gradient(circle at 20% 0%, rgba(174,182,154,.45), transparent 32rem), + linear-gradient(135deg, #e8e5dc, #cbcfc3); +} + +.phone-shell { + position: relative; + width: min(100%, 430px); + min-height: 100dvh; + height: 100dvh; + overflow: hidden; + background: var(--cream); + box-shadow: 0 0 60px rgba(47, 52, 39, .22); +} + +.paper-texture { + position: absolute; inset: 0; pointer-events: none; opacity: .19; + background: url('./assets/paper-bg.webp') center top / 920px auto repeat-y; + mix-blend-mode: multiply; +} + +.topbar { + position: relative; z-index: 5; height: 76px; padding: max(14px, env(safe-area-inset-top)) 22px 10px; + display: flex; align-items: center; justify-content: space-between; + background: linear-gradient(to bottom, rgba(255,253,248,.96), rgba(255,253,248,.76)); + backdrop-filter: blur(12px); +} + +.brand { display: inline-flex; align-items: center; gap: 10px; color: var(--olive); font: 700 25px/1 Georgia, "Noto Serif SC", serif; } +.brand-mark { position: relative; width: 31px; height: 28px; display: flex; gap: 2px; align-items: end; } +.brand-mark i { width: 15px; height: 24px; background: var(--olive); border-radius: 3px 8px 3px 4px; transform: skewY(9deg); box-shadow: inset -2px 0 rgba(255,255,255,.3); } +.brand-mark i + i { transform: scaleX(-1) skewY(9deg); } +.brand-mark::after { content: '◆'; position: absolute; color: #eef0dd; font-size: 7px; left: 12px; top: 8px; } +.top-actions { display: flex; align-items: center; gap: 10px; } +.icon-button { width: 42px; height: 42px; border: 0; background: transparent; color: var(--olive); position: relative; } +.bell span { position: absolute; width: 17px; height: 20px; border: 2px solid currentColor; border-radius: 10px 10px 6px 6px; left: 12px; top: 9px; } +.bell span::after { content: ''; width: 5px; height: 3px; background: currentColor; border-radius: 50%; position: absolute; bottom: -5px; left: 4px; } +.bell::after { content: ''; position: absolute; width: 7px; height: 7px; background: #d7654d; border: 2px solid var(--paper); border-radius: 50%; right: 6px; top: 6px; } +.mini-avatar { width: 38px; height: 38px; border: 2px solid var(--border); background: linear-gradient(145deg, var(--sage), var(--soft-sage)); color: white; border-radius: 50%; display: grid; place-items: center; font: 700 16px Georgia, serif; } + +.content-scroll { position: relative; height: calc(100dvh - 76px); overflow-y: auto; overscroll-behavior: contain; padding: 6px 18px 112px; scrollbar-width: none; } +.content-scroll::-webkit-scrollbar { display: none; } +.search-box { min-height: 52px; display: flex; align-items: center; gap: 12px; padding: 0 16px; border: 1px solid rgba(181,163,126,.72); border-radius: 18px; background: rgba(255,253,248,.91); color: #8b887e; box-shadow: 0 6px 18px rgba(93,81,57,.07); } +.search-box kbd { margin-left: auto; font: 500 11px system-ui; padding: 4px 7px; border: 1px solid #ddd4c3; border-radius: 7px; color: #9c988e; } +.search-icon { width: 20px; height: 20px; border: 2px solid var(--olive); border-radius: 50%; position: relative; flex: 0 0 auto; } +.search-icon::after { content: ''; position: absolute; width: 8px; height: 2px; background: var(--olive); transform: rotate(45deg); right: -6px; bottom: -3px; border-radius: 2px; } + +.category-chips { display: flex; gap: 9px; overflow-x: auto; padding: 13px 1px 12px; scrollbar-width: none; } +.category-chips::-webkit-scrollbar { display: none; } +.chip { white-space: nowrap; padding: 8px 14px; border: 1px solid rgba(213,199,167,.75); border-radius: 999px; color: #5e6057; background: rgba(255,253,248,.72); font-size: 13px; } +.chip.active { color: white; background: var(--sage); border-color: var(--sage); box-shadow: 0 5px 12px rgba(79,89,64,.18); } + +.hero-card { position: relative; min-height: 207px; border-radius: 25px; overflow: hidden; border: 1px solid rgba(213,199,167,.85); background: linear-gradient(128deg, #edf0df 0%, #e3e8d5 55%, #cad1b7 100%); box-shadow: var(--shadow); } +.hero-card::before { content: ''; position: absolute; inset: 0; background: radial-gradient(circle at 75% 30%, rgba(255,255,255,.9), transparent 32%), repeating-linear-gradient(120deg, transparent 0 24px, rgba(255,255,255,.13) 25px 26px); } +.hero-copy { position: relative; z-index: 2; width: 62%; padding: 23px 0 21px 22px; } +.eyebrow { margin: 0 0 7px; color: #829071; letter-spacing: .12em; font-size: 10px; font-weight: 700; } +.hero-copy h1 { margin: 0; color: var(--olive); font: 700 27px/1.28 "Noto Serif SC", "Songti SC", serif; letter-spacing: .03em; } +.hero-copy > p:not(.eyebrow) { margin: 9px 0 15px; color: #6e7365; font-size: 11px; line-height: 1.6; } +.hero-button { display: inline-flex; align-items: center; gap: 10px; padding: 8px 14px; border-radius: 999px; background: var(--olive); color: white; font-size: 12px; box-shadow: 0 6px 14px rgba(79,89,64,.2); } +.hero-button span { color: #e9dcae; } +.hero-tobby { position: absolute; z-index: 1; width: 177px; height: 177px; object-fit: contain; right: -24px; bottom: -13px; filter: drop-shadow(0 10px 10px rgba(69,71,53,.12)); } + +.section-block { margin-top: 21px; } +.section-title { display: flex; align-items: center; justify-content: space-between; margin-bottom: 11px; } +.section-title h2 { margin: 0; color: var(--olive); font: 700 18px/1.2 "Noto Serif SC", "Songti SC", serif; } +.section-title h2::before { content: '❧'; margin-right: 7px; color: var(--sage); } +.section-title a, .section-title > span { color: #8a877c; font-size: 12px; } +.book-row { display: grid; grid-auto-flow: column; grid-auto-columns: 42%; gap: 12px; overflow-x: auto; padding: 1px 1px 10px; scroll-snap-type: x mandatory; scrollbar-width: none; } +.book-row::-webkit-scrollbar { display: none; } +.book-tile { scroll-snap-align: start; border: 1px solid rgba(213,199,167,.62); border-radius: 17px; background: rgba(255,253,248,.87); padding: 9px; box-shadow: 0 8px 20px rgba(82,78,59,.07); } +.book-cover { height: 142px; position: relative; overflow: hidden; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; padding: 14px; border-radius: 10px 14px 14px 9px; color: #35402f; background: linear-gradient(145deg, #aeb99d, #e5e8d8); box-shadow: inset 5px 0 rgba(255,255,255,.25); } +.book-cover::after { content: ''; position: absolute; width: 100px; height: 100px; border: 1px solid rgba(255,255,255,.3); border-radius: 50%; right: -48px; bottom: -50px; } +.book-cover.paper { background: linear-gradient(145deg, #f3eee0, #c8ceb7); } +.book-cover.ink { color: #eef0e5; background: linear-gradient(145deg, #596252, #9aa28a); } +.cover-leaf { font-size: 25px; margin-bottom: 6px; } +.book-cover strong { font: 700 15px/1.35 "Noto Serif SC", serif; } +.book-cover small { margin-top: 9px; font-size: 7px; letter-spacing: .08em; opacity: .75; } +.book-tile h3 { min-height: 38px; margin: 9px 1px 1px; font-size: 13px; line-height: 1.45; } +.book-tile > p { margin: 0; color: var(--muted); font-size: 10px; } +.book-meta { display: flex; justify-content: space-between; align-items: center; margin-top: 7px; } +.book-meta strong { color: var(--price); font: 700 15px Georgia, serif; } +.book-meta span { padding: 3px 6px; border-radius: 6px; background: #eef0e2; color: #687159; font-size: 9px; } + +.ranking-card { margin: 13px 0 18px; padding: 16px; border: 1px solid rgba(213,199,167,.68); border-radius: 20px; background: rgba(255,253,248,.84); box-shadow: 0 8px 22px rgba(82,78,59,.06); } +.rank-item { display: grid; grid-template-columns: 34px 1fr auto; gap: 9px; align-items: center; padding: 11px 0; border-top: 1px dashed rgba(213,199,167,.72); } +.rank-number { color: var(--gold); font: italic 700 15px Georgia, serif; } +.rank-item div { min-width: 0; } +.rank-item strong, .rank-item small { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.rank-item strong { font-size: 12px; } +.rank-item small { margin-top: 3px; color: var(--muted); font-size: 9px; } +.rank-item b { color: var(--price); font: 700 13px Georgia, serif; } + +.bottom-nav { position: absolute; z-index: 10; left: 12px; right: 12px; bottom: max(10px, env(safe-area-inset-bottom)); height: 72px; display: grid; grid-template-columns: repeat(5, 1fr); align-items: end; padding: 8px 7px 7px; border: 1px solid rgba(213,199,167,.84); border-radius: 25px; background: rgba(255,253,248,.94); box-shadow: 0 12px 32px rgba(64,67,53,.18); backdrop-filter: blur(16px); } +.nav-item { min-height: 51px; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; gap: 4px; color: #707268; font-size: 10px; position: relative; } +.nav-item.active { color: var(--olive); font-weight: 700; } +.nav-item.publish { transform: translateY(-9px); } +.nav-item.publish::before { content: ''; position: absolute; z-index: -1; width: 54px; height: 54px; bottom: -1px; border: 5px solid var(--paper); border-radius: 50%; background: var(--sage); box-shadow: 0 0 0 1px var(--border), 0 7px 16px rgba(79,89,64,.23); } +.nav-item.publish { color: white; } +.nav-icon { width: 20px; height: 20px; position: relative; display: block; } +.nav-icon.home { border: 2px solid currentColor; border-top: 0; border-radius: 2px; margin-top: 5px; } +.nav-icon.home::before { content: ''; position: absolute; width: 15px; height: 15px; border-left: 2px solid currentColor; border-top: 2px solid currentColor; transform: rotate(45deg); left: 1px; top: -7px; } +.nav-icon.grid { background: radial-gradient(circle, currentColor 0 3px, transparent 3.5px) 0 0 / 10px 10px; } +.nav-icon.send { width: 0; height: 0; border-left: 19px solid currentColor; border-top: 8px solid transparent; border-bottom: 8px solid transparent; transform: rotate(-35deg); } +.nav-icon.chat { border: 2px solid currentColor; border-radius: 7px; } +.nav-icon.chat::after { content: ''; position: absolute; border-top: 5px solid currentColor; border-right: 5px solid transparent; left: 2px; bottom: -5px; } +.nav-icon.user { border: 2px solid currentColor; border-radius: 50% 50% 42% 42%; height: 11px; margin-top: 10px; } +.nav-icon.user::before { content: ''; position: absolute; width: 8px; height: 8px; border: 2px solid currentColor; border-radius: 50%; left: 4px; top: -11px; background: var(--paper); } + +@media (max-width: 370px) { + .topbar { padding-left: 16px; padding-right: 16px; } + .content-scroll { padding-left: 14px; padding-right: 14px; } + .brand { font-size: 22px; } + .hero-copy h1 { font-size: 24px; } + .hero-tobby { width: 162px; height: 162px; } +} + +@media (prefers-reduced-motion: no-preference) { + .hero-tobby { animation: float 4s ease-in-out infinite; } + .chip, .book-tile, .hero-button { transition: transform .2s ease, box-shadow .2s ease; } + .chip:active, .hero-button:active { transform: scale(.96); } +} + +@media (prefers-reduced-motion: reduce) { + *, *::before, *::after { scroll-behavior: auto !important; animation: none !important; transition: none !important; } +} + +@keyframes float { 0%, 100% { transform: translateY(0) rotate(-1deg); } 50% { transform: translateY(-5px) rotate(1deg); } } + +/* Shared application chrome */ +.brand-button { padding: 0; border: 0; background: transparent; } +.round-button { width: 43px; height: 43px; display: grid; place-items: center; padding: 0; border: 1px solid rgba(213,199,167,.65); border-radius: 50%; background: rgba(255,253,248,.8); } +.top-actions .icon-button { display: grid; place-items: center; padding: 0; } +.notification-dot { position: absolute; top: 7px; right: 5px; width: 8px; height: 8px; border: 2px solid var(--paper); border-radius: 50%; background: #df6752; } +.page-topbar { display: grid; grid-template-columns: 1fr auto 1fr; } +.page-topbar .brand > span:last-child { display: none; } +.page-topbar h1 { margin: 0; font: 700 20px/1.2 "Noto Serif SC", "Songti SC", serif; white-space: nowrap; } +.page-topbar .top-actions { justify-content: flex-end; } +.bottom-nav button { border: 0; background: transparent; } +.avatar { flex: 0 0 auto; overflow: hidden; display: inline-grid; place-items: center; border: 2px solid var(--paper); border-radius: 50%; color: white; font-weight: 700; box-shadow: 0 0 0 1px var(--border); } +.avatar img { width: 100%; height: 100%; object-fit: cover; } +.image-avatar { background: #dde1c9; } +.image-avatar img { width: 126%; height: 126%; object-fit: contain; transform: translateY(7%); } +.avatar-sage { background: linear-gradient(145deg, #69765c, #a9b697); } +.avatar-peach { background: linear-gradient(145deg, #c9987c, #e6cabb); } +.avatar-blue { background: linear-gradient(145deg, #708995, #b9cbd0); } +.avatar-gold { background: linear-gradient(145deg, #bc9553, #e2c894); } +.avatar-olive { background: linear-gradient(145deg, #54604a, #8b9b7b); } +.primary-button, .secondary-button { min-height: 48px; display: inline-flex; align-items: center; justify-content: center; gap: 8px; padding: 0 20px; border-radius: 17px; font-weight: 700; } +.primary-button { border: 1px solid #586246; background: linear-gradient(145deg, #76805e, #5f6b4b); color: white; box-shadow: 0 9px 20px rgba(79,89,64,.2), inset 0 1px rgba(255,255,255,.25); } +.secondary-button { border: 1px solid var(--border); background: rgba(255,253,248,.88); color: #6f705f; } +.primary-button:disabled { opacity: .48; cursor: not-allowed; } +.toast { position: fixed; z-index: 100; left: 50%; bottom: 105px; transform: translateX(-50%); width: min(calc(100% - 52px), 350px); min-height: 46px; display: flex; align-items: center; justify-content: center; gap: 8px; padding: 10px 14px; border: 1px solid var(--border); border-radius: 15px; background: rgba(255,253,248,.96); color: var(--olive); box-shadow: 0 15px 35px rgba(57,61,47,.22); backdrop-filter: blur(14px); font-size: 13px; } +.spin { animation: spin 1s linear infinite; } +@keyframes spin { to { transform: rotate(360deg); } } + +/* Welcome */ +.welcome-page { min-height: 100dvh; overflow-y: auto; padding: 25px 24px 30px; background: linear-gradient(#fffdf8dd, #faf6ead9), url('./assets/paper-bg.webp') center / cover; } +.welcome-decoration { position: absolute; inset: 0; pointer-events: none; background: radial-gradient(circle at 90% 26%, rgba(174,182,154,.2), transparent 25%), radial-gradient(circle at 4% 70%, rgba(213,199,167,.22), transparent 22%); } +.welcome-brand { position: relative; display: flex; justify-content: space-between; align-items: center; } +.leaf-seal { width: 42px; height: 42px; display: grid; place-items: center; border: 1px solid var(--border); border-radius: 50%; color: var(--sage); background: rgba(255,253,248,.6); } +.welcome-copy { position: relative; z-index: 2; margin-top: 33px; } +.welcome-copy > span { display: inline-flex; align-items: center; gap: 5px; padding: 8px 14px; border: 1px solid var(--border); border-radius: 18px; background: rgba(255,253,248,.76); color: #656a59; font-size: 12px; } +.welcome-copy h1 { margin: 13px 0 10px; font: 700 36px/1.25 "Noto Serif SC", "Songti SC", serif; color: #4e5248; } +.welcome-copy h1 em { color: var(--sage); font-style: normal; } +.welcome-copy p { margin: 0; color: var(--muted); font-size: 13px; line-height: 1.85; } +.welcome-tobby { position: relative; z-index: 1; width: 68%; height: auto; display: block; margin: -36px -27px -43px auto; filter: drop-shadow(0 14px 14px rgba(66,70,52,.12)); } +.welcome-steps { position: relative; z-index: 3; display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; padding: 17px 8px; border: 1px solid rgba(213,199,167,.76); border-radius: 23px; background: rgba(255,253,248,.9); box-shadow: var(--shadow); } +.welcome-steps div { min-width: 0; display: flex; flex-direction: column; align-items: center; text-align: center; position: relative; } +.welcome-steps div:not(:last-child)::after { content: '→'; position: absolute; right: -7px; top: 12px; color: #c9bc9c; } +.welcome-steps small { color: #a89b7b; font: 700 10px Georgia, serif; } +.welcome-steps svg { width: 25px; margin: 6px 0; color: var(--sage); } +.welcome-steps strong { font: 700 14px "Noto Serif SC", serif; } +.welcome-steps span { margin-top: 3px; color: var(--muted); font-size: 8px; white-space: nowrap; } +.welcome-actions { position: relative; display: grid; gap: 10px; margin-top: 18px; } +.welcome-actions button { width: 100%; } +.welcome-actions p { margin: 7px 0 0; text-align: center; color: #8f8c80; font-size: 10px; } + +/* Onboarding */ +.onboarding-page { background: var(--cream); } +.onboarding-preview { position: absolute; inset: 0; padding: 30px 18px 100px; filter: blur(.5px); } +.fake-brand { height: 50px; } +.fake-search { height: 52px; border: 1px solid var(--border); border-radius: 18px; background: white; } +.fake-hero { height: 210px; margin-top: 18px; border-radius: 24px; background: linear-gradient(140deg, #d8deca, #a5b093); } +.fake-cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin-top: 22px; } +.fake-cards i { height: 180px; border: 1px solid #ddd2b8; border-radius: 17px; background: #fffdf8; } +.fake-nav { position: absolute; left: 15px; right: 15px; bottom: 15px; height: 72px; border-radius: 24px; background: white; } +.onboarding-scrim { position: absolute; inset: 0; background: rgba(40,42,36,.69); backdrop-filter: blur(2px); } +.onboarding-panel { position: relative; z-index: 2; height: 100%; display: flex; flex-direction: column; padding: max(22px, env(safe-area-inset-top)) 24px 28px; color: var(--text); } +.onboarding-heading { display: flex; align-items: center; justify-content: space-between; color: white; } +.onboarding-heading span { font: 700 24px "Noto Serif SC", serif; } +.onboarding-heading button { min-height: 42px; padding: 0 15px; border: 1px solid rgba(255,255,255,.6); border-radius: 15px; background: rgba(255,255,255,.15); color: white; } +.onboarding-panel > img { width: 80%; height: auto; margin: auto auto -17px; filter: drop-shadow(0 20px 18px rgba(0,0,0,.2)); } +.guide-card { border: 1px solid var(--border); border-radius: 25px; padding: 22px; background: rgba(255,253,248,.97); box-shadow: 0 18px 46px rgba(0,0,0,.25); text-align: center; } +.guide-card small { color: var(--gold); font: 700 10px Georgia, serif; letter-spacing: .16em; } +.guide-card h1 { margin: 7px 0; color: var(--olive); font: 700 24px "Noto Serif SC", serif; } +.guide-card p { margin: 0; color: var(--muted); font-size: 12px; line-height: 1.7; } +.guide-pills { display: flex; justify-content: center; flex-wrap: wrap; gap: 6px; margin-top: 13px; } +.guide-pills span { display: flex; align-items: center; gap: 3px; padding: 5px 8px; border-radius: 999px; background: #eef0e2; color: #677056; font-size: 9px; } +.step-dots { display: flex; justify-content: center; gap: 7px; margin: 17px 0; } +.step-dots i { width: 7px; height: 7px; border-radius: 50%; background: rgba(255,255,255,.45); } +.step-dots i.active { width: 22px; border-radius: 8px; background: white; } +.guide-actions { display: flex; gap: 10px; } +.guide-actions button { flex: 1; } + +/* Search and listings */ +.search-input { min-height: 54px; display: flex; align-items: center; gap: 11px; padding: 0 14px; border: 1px solid rgba(181,163,126,.75); border-radius: 18px; background: rgba(255,253,248,.92); box-shadow: 0 5px 14px rgba(91,80,59,.06); } +.search-input svg { color: var(--olive); } +.search-input input { min-width: 0; flex: 1; border: 0; outline: 0; background: transparent; color: var(--text); font-size: 13px; } +.search-input button { width: 34px; height: 34px; display: grid; place-items: center; border: 0; background: transparent; } +.quick-filters { display: flex; gap: 7px; overflow-x: auto; padding: 2px 1px 12px; scrollbar-width: none; } +.quick-filters button { min-height: 36px; display: inline-flex; align-items: center; gap: 3px; white-space: nowrap; padding: 0 11px; border: 1px solid rgba(213,199,167,.68); border-radius: 12px; background: rgba(255,253,248,.74); color: #62645b; font-size: 10px; } +.quick-filters button svg { width: 12px; } +.quick-filters .filter-trigger { margin-left: auto; border-color: var(--sage); color: var(--olive); } +.results-heading { display: flex; justify-content: space-between; align-items: end; margin: 3px 2px 12px; } +.results-heading h2 { margin: 0; font: 700 17px "Noto Serif SC", serif; } +.results-heading h2 em { color: var(--price); font-style: normal; } +.results-heading span { color: var(--muted); font-size: 9px; } +.listing-stack { display: grid; gap: 12px; } +.listing-card { position: relative; padding: 11px; overflow: hidden; border: 1px solid rgba(213,199,167,.62); border-radius: 21px; background: rgba(255,253,248,.88); box-shadow: 0 8px 20px rgba(70,71,54,.07); } +.listing-main { width: 100%; display: grid; grid-template-columns: 112px 1fr; gap: 13px; padding: 0; border: 0; background: transparent; text-align: left; } +.listing-main .book-cover { width: 112px; height: 151px; } +.listing-copy { min-width: 0; padding: 3px 0; } +.listing-heading { display: flex; justify-content: space-between; gap: 8px; } +.listing-heading h3 { margin: 0; font-size: 14px; line-height: 1.45; } +.listing-copy > p { margin: 4px 0 9px; color: var(--muted); font-size: 10px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.listing-price { display: flex; align-items: center; gap: 7px; margin-bottom: 8px; } +.listing-price strong { color: var(--olive); font: 700 20px Georgia, serif; } +.listing-price del { color: #aaa69b; font-size: 9px; } +.listing-price span { margin-left: auto; padding: 4px 7px; border: 1px solid #d7cfb2; border-radius: 8px; color: #697357; font-size: 9px; } +.listing-detail { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; color: #787a70; font-size: 9px; line-height: 1.7; } +.seller-line { display: flex; align-items: center; gap: 5px; margin-top: 9px; color: #6e7166; font-size: 9px; } +.seller-line svg { color: #d2a956; } +.listing-actions { display: grid; grid-template-columns: 1fr 1.1fr 1fr; gap: 7px; margin-top: 10px; } +.listing-actions button { min-height: 38px; display: flex; align-items: center; justify-content: center; gap: 4px; border: 1px solid rgba(213,199,167,.8); border-radius: 13px; background: transparent; color: #686b5f; font-size: 10px; } +.listing-actions .detail-action { background: var(--sage); color: white; border-color: var(--sage); } +.status-badge { position: absolute; z-index: 2; left: 5px; top: 5px; padding: 5px 8px; border-radius: 8px; background: rgba(93,110,75,.92); color: white; font-size: 8px; } +.status-badge.sold, .status-pill.sold { background: #77776f; } +.status-badge.offline, .status-pill.offline { background: #a67e65; } +.unavailable-card .listing-main { opacity: .62; } +.inline-state { min-height: 410px; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; } +.inline-state img { width: 190px; height: 190px; object-fit: contain; } +.inline-state h3 { margin: -12px 0 5px; font: 700 18px "Noto Serif SC", serif; } +.inline-state p { max-width: 260px; color: var(--muted); font-size: 11px; line-height: 1.7; } +.inline-state .secondary-button, .inline-state .primary-button { margin-top: 10px; } +.inline-state.large { min-height: 620px; } +.loading-bar { width: 150px; height: 6px; overflow: hidden; display: block; margin-top: 15px; border-radius: 10px; background: #e1ddce; } +.loading-bar i { display: block; width: 45%; height: 100%; border-radius: 10px; background: linear-gradient(90deg, var(--sage), var(--aqua)); animation: loading 1.2s ease-in-out infinite alternate; } +@keyframes loading { to { transform: translateX(120%); } } + +/* Filter sheet */ +.sheet-layer { position: absolute; z-index: 40; inset: 0; display: flex; align-items: flex-end; } +.sheet-scrim { position: absolute; inset: 0; width: 100%; border: 0; background: rgba(45,47,39,.44); backdrop-filter: blur(2px); } +.filter-sheet { position: relative; z-index: 1; width: 100%; max-height: 82%; overflow-y: auto; padding: 10px 18px max(22px, env(safe-area-inset-bottom)); border: 1px solid var(--border); border-radius: 26px 26px 0 0; background: #fffdf8; box-shadow: 0 -18px 50px rgba(42,45,37,.22); } +.sheet-handle { width: 42px; height: 4px; margin: 0 auto 9px; border-radius: 5px; background: #cfc8b9; } +.sheet-title { display: grid; grid-template-columns: 1fr auto auto; align-items: center; gap: 8px; } +.sheet-title h2 { display: flex; align-items: center; gap: 5px; margin: 0; color: var(--olive); font: 700 19px "Noto Serif SC", serif; } +.sheet-title button { min-height: 38px; display: flex; align-items: center; gap: 3px; border: 0; background: transparent; color: #817d71; font-size: 10px; } +.range-label { display: grid; grid-template-columns: 1fr auto; gap: 10px; margin: 14px 0; font-size: 11px; } +.range-label strong { color: var(--olive); } +.range-label input { grid-column: 1 / -1; width: 100%; accent-color: var(--sage); } +.filter-group { margin: 13px 0; } +.filter-group > strong { display: block; margin-bottom: 7px; font-size: 12px; } +.filter-group > div { display: flex; flex-wrap: wrap; gap: 7px; } +.filter-group button { min-height: 33px; padding: 0 12px; border: 1px solid #e1d7c1; border-radius: 999px; background: #fbf8ef; color: #6b6d63; font-size: 10px; } +.filter-group button.active { border-color: var(--sage); background: var(--sage); color: white; } +.switch-row { min-height: 42px; display: flex; align-items: center; justify-content: space-between; position: relative; font-size: 12px; } +.switch-row input { position: absolute; opacity: 0; } +.switch-row i { width: 46px; height: 26px; padding: 3px; border-radius: 999px; background: #d8d5ca; } +.switch-row i::after { content: ''; display: block; width: 20px; height: 20px; border-radius: 50%; background: white; box-shadow: 0 2px 5px rgba(0,0,0,.18); transition: transform .2s; } +.switch-row input:checked + i { background: var(--sage); } +.switch-row input:checked + i::after { transform: translateX(20px); } +.apply-filter { width: 100%; margin-top: 10px; } + +/* Detail */ +.detail-gallery { position: relative; min-height: 285px; display: flex; gap: 8px; overflow-x: auto; padding: 6px; border: 1px solid rgba(213,199,167,.62); border-radius: 24px; background: rgba(255,253,248,.75); } +.detail-gallery > .book-cover { min-width: 100%; height: 275px; } +.detail-gallery > img { width: 100%; flex: 0 0 100%; object-fit: cover; border-radius: 19px; } +.detail-gallery > span { position: absolute; left: 15px; top: 15px; padding: 7px 11px; border-radius: 10px; background: rgba(76,76,69,.88); color: white; font-size: 10px; } +.detail-card { margin-top: 12px; padding: 18px; border: 1px solid rgba(213,199,167,.68); border-radius: 22px; background: rgba(255,253,248,.9); } +.detail-title { display: flex; justify-content: space-between; gap: 10px; } +.detail-title h1 { margin: 7px 0 3px; font: 700 21px/1.35 "Noto Serif SC", serif; } +.detail-title p { margin: 0; color: var(--muted); font-size: 11px; } +.detail-title > button { width: 43px; height: 43px; display: grid; place-items: center; border: 1px solid var(--border); border-radius: 50%; background: #fffdf8; color: var(--price); } +.status-pill { padding: 4px 7px; border-radius: 7px; background: var(--sage); color: white; font-size: 9px; } +.detail-price { display: flex; align-items: center; gap: 10px; margin: 15px 0; } +.detail-price strong { color: var(--price); font: 700 27px Georgia, serif; } +.detail-price del { color: #a6a195; font-size: 11px; } +.detail-price span { margin-left: auto; padding: 5px 8px; border: 1px solid #d8cfb5; border-radius: 8px; color: #657054; font-size: 10px; } +.detail-facts { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; } +.detail-facts span { display: flex; align-items: center; gap: 5px; color: #6d7065; font-size: 10px; } +.detail-facts svg { width: 15px; } +.detail-facts span:last-child { grid-column: 1 / -1; } +.description-block { margin-top: 19px; padding-top: 15px; border-top: 1px dashed var(--border); } +.description-block h2 { margin: 0; font: 700 15px "Noto Serif SC", serif; } +.description-block p { color: #62645c; font-size: 11px; line-height: 1.8; } +.description-block div { display: flex; gap: 6px; flex-wrap: wrap; } +.description-block span { padding: 5px 8px; border-radius: 999px; background: #f0eee3; color: #707364; font-size: 9px; } +.seller-card { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 11px; margin-top: 12px; padding: 15px; border: 1px solid rgba(213,199,167,.68); border-radius: 20px; background: rgba(255,253,248,.85); } +.seller-card h3 { display: flex; align-items: center; gap: 5px; margin: 0; font-size: 14px; } +.seller-card h3 svg { width: 15px; color: var(--sage); } +.seller-card p { margin: 4px 0; color: var(--muted); font-size: 9px; } +.seller-card span { color: #79806b; font-size: 8px; } +.seller-card > button { min-height: 38px; padding: 0 13px; border: 1px solid var(--sage); border-radius: 12px; background: #f5f6ec; color: var(--olive); } +.safety-note { display: flex; align-items: flex-start; gap: 7px; margin: 12px 0; padding: 11px 13px; border-radius: 14px; background: #edf0e3; color: #657054; font-size: 9px; line-height: 1.6; } +.safety-note svg { width: 16px; flex: 0 0 auto; } +.detail-cta { position: sticky; bottom: 87px; display: grid; grid-template-columns: 88px 1fr; gap: 9px; padding: 9px; border: 1px solid var(--border); border-radius: 20px; background: rgba(255,253,248,.95); box-shadow: var(--shadow); backdrop-filter: blur(10px); } +.detail-cta > button:first-child { display: flex; align-items: center; justify-content: center; gap: 4px; border: 0; background: transparent; color: #777269; font-size: 10px; } + +/* Publish */ +.stepper { display: grid; grid-template-columns: repeat(3, 1fr); margin: 0 0 16px; } +.stepper > div { position: relative; display: flex; flex-direction: column; align-items: center; color: #aaa69c; } +.stepper span { width: 28px; height: 28px; display: grid; place-items: center; border: 1px solid #d9cfb9; border-radius: 50%; background: #fffdf8; font: 700 11px Georgia, serif; } +.stepper p { margin: 5px 0 0; font-size: 9px; } +.stepper i { position: absolute; width: calc(100% - 38px); height: 1px; left: calc(50% + 19px); top: 14px; background: #d9cfb9; } +.stepper .active { color: var(--olive); } +.stepper .active span { border-color: var(--sage); background: var(--sage); color: white; } +.upload-card, .form-card, .publish-preview { padding: 15px; border: 1px solid rgba(213,199,167,.68); border-radius: 22px; background: rgba(255,253,248,.88); box-shadow: 0 8px 20px rgba(72,72,56,.06); } +.image-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; } +.upload-preview, .add-image { position: relative; aspect-ratio: .77; overflow: hidden; border-radius: 13px; } +.upload-preview img { width: 100%; height: 100%; object-fit: cover; } +.upload-preview button { position: absolute; right: 3px; top: 3px; width: 25px; height: 25px; display: grid; place-items: center; padding: 0; border: 0; border-radius: 50%; background: rgba(48,50,41,.65); color: white; } +.upload-preview button svg { width: 14px; } +.add-image { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; border: 1px dashed var(--border); background: #fbf9f2; color: var(--olive); } +.add-image svg { width: 28px; } +.add-image strong { font-size: 11px; } +.add-image span { color: var(--muted); font-size: 8px; } +.tobby-tip { min-height: 74px; display: flex; align-items: center; gap: 5px; margin-top: 8px; } +.tobby-tip img { width: 92px; height: 80px; object-fit: contain; align-self: end; } +.tobby-tip span { padding: 9px 12px; border: 1px solid #ded2b6; border-radius: 16px 16px 16px 4px; color: #6b6d62; font-size: 10px; background: white; } +.ai-card { display: grid; grid-template-columns: 1fr auto; gap: 10px; align-items: center; margin-top: 12px; padding: 14px; border: 1px solid #d7ccb3; border-radius: 19px; background: linear-gradient(120deg, #fffaf0, #edf1e2); } +.ai-card p { display: flex; align-items: center; gap: 5px; margin: 0 0 4px; color: var(--olive); font: 700 14px "Noto Serif SC", serif; } +.ai-card p svg { width: 16px; color: var(--gold); } +.ai-card span { color: var(--muted); font-size: 8px; line-height: 1.5; } +.ai-card button { min-height: 42px; display: flex; align-items: center; gap: 5px; padding: 0 11px; border: 1px solid var(--olive); border-radius: 13px; background: var(--sage); color: white; font-size: 9px; } +.ai-card button svg { width: 16px; } +.form-card { display: grid; gap: 12px; } +.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 11px; } +.form-field { display: grid; gap: 5px; color: #56594f; font-size: 10px; } +.form-field > span { font-weight: 700; } +.form-field em { margin-right: 3px; color: #db5f4d; font-style: normal; } +.form-field input, .form-field select, .form-field textarea { width: 100%; min-height: 43px; padding: 9px 11px; border: 1px solid #dfd4bd; border-radius: 12px; outline: none; background: rgba(255,255,255,.76); color: var(--text); font-size: 11px; resize: vertical; } +.form-field textarea { min-height: 105px; } +.form-field input:focus, .form-field select:focus, .form-field textarea:focus { border-color: var(--sage); box-shadow: 0 0 0 3px rgba(111,121,86,.11); } +.form-field.error input, .form-field.error textarea { border-color: #cf6f5f; } +.tag-picker { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; } +.tag-picker > span { color: var(--muted); font-size: 9px; } +.tag-picker button { min-height: 31px; padding: 0 9px; border: 1px solid #e0d7c3; border-radius: 999px; background: #f8f5ec; font-size: 9px; } +.tag-picker button.active { border-color: var(--sage); background: #e8ecdb; color: var(--olive); } +.form-error { display: flex; align-items: center; gap: 5px; padding: 9px; border-radius: 10px; background: #fff0eb; color: #ad5145; font-size: 9px; } +.form-error svg { width: 15px; } +.publish-actions { display: flex; gap: 8px; margin: 13px 0 15px; } +.publish-actions button { flex: 1; } +.publish-preview > .eyebrow { margin-bottom: 10px; } + +/* Messages and chat */ +.notification-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 9px; } +.notification-grid > button { min-height: 105px; display: grid; grid-template-columns: 44px 1fr; align-items: center; gap: 8px; position: relative; padding: 12px; border: 1px solid rgba(213,199,167,.63); border-radius: 19px; background: rgba(255,253,248,.87); text-align: left; box-shadow: 0 7px 17px rgba(68,69,54,.06); } +.notice-icon { width: 42px; height: 42px; display: grid; place-items: center; border-radius: 50%; background: #eef0e3; color: var(--sage); } +.notice-icon.like { background: #fff0ec; color: #df7564; }.notice-icon.system { background: #fff6dd; color: #d69d40; }.notice-icon.follow { background: #edf1e6; } +.notice-icon svg { width: 22px; } +.notification-grid strong { font: 700 13px "Noto Serif SC", serif; } +.notification-grid p { margin: 5px 0 0; color: var(--muted); font-size: 8px; } +.notification-grid b { position: absolute; right: 8px; top: 8px; width: 20px; height: 20px; display: grid; place-items: center; border-radius: 50%; background: #e69a4f; color: white; font-size: 9px; } +.message-title { margin: 20px 2px 9px; } +.message-title > span { display: flex; align-items: center; } +.thread-list { display: grid; gap: 7px; } +.thread-list > button { min-height: 78px; display: grid; grid-template-columns: auto 1fr auto; gap: 10px; align-items: center; position: relative; padding: 10px; border: 1px solid rgba(213,199,167,.55); border-radius: 17px; background: rgba(255,253,248,.82); text-align: left; } +.thread-list div { min-width: 0; } +.thread-list h3 { margin: 0; font-size: 13px; } +.thread-list h3 span { margin-left: 6px; padding: 3px 6px; border: 1px solid #dfd4bd; border-radius: 7px; color: #8b7d64; font-size: 8px; font-weight: 400; } +.thread-list p { margin: 6px 0 0; overflow: hidden; color: var(--muted); font-size: 9px; text-overflow: ellipsis; white-space: nowrap; } +.thread-list time { align-self: start; padding-top: 4px; color: #99958c; font-size: 8px; } +.thread-list b { position: absolute; right: 10px; bottom: 10px; width: 20px; height: 20px; display: grid; place-items: center; border-radius: 50%; background: #e5924b; color: white; font-size: 8px; } +.tobby-banner { min-height: 73px; display: flex; align-items: center; margin-top: 15px; padding: 8px 12px 8px 85px; position: relative; border: 1px solid var(--border); border-radius: 17px; background: rgba(255,253,248,.86); } +.tobby-banner img { position: absolute; width: 96px; height: 96px; object-fit: contain; left: -4px; bottom: -3px; } +.tobby-banner span { color: #6b6f61; font-size: 9px; line-height: 1.6; } +.chat-page .page-topbar { height: 68px; } +.chat-page .content-scroll { height: calc(100dvh - 68px); padding: 0 15px 82px; } +.chat-user { display: flex; align-items: center; gap: 8px; padding: 0 5px 7px; color: #7c806f; font-size: 9px; } +.chat-safety { width: fit-content; display: flex; align-items: center; gap: 6px; margin: 7px auto 18px; padding: 8px 12px; border: 1px solid #dbd1b9; border-radius: 999px; color: #6a715d; font-size: 9px; background: rgba(255,253,248,.8); } +.chat-safety svg { width: 15px; } +.message-stream { display: grid; gap: 13px; } +.message-row { display: flex; align-items: flex-end; gap: 8px; } +.message-row.mine { justify-content: flex-end; } +.message-row > div { max-width: 72%; } +.message-row p { margin: 0; padding: 10px 12px; border: 1px solid #ded4be; border-radius: 6px 16px 16px 16px; background: rgba(255,253,248,.91); font-size: 11px; line-height: 1.6; } +.message-row.mine p { border-color: #cbd1b5; border-radius: 16px 6px 16px 16px; background: #e8ecdc; } +.message-row time { display: block; margin-top: 4px; color: #99968d; font-size: 8px; } +.message-row.mine time { text-align: right; } +.shared-book { width: 100%; display: grid; grid-template-columns: 64px 1fr; gap: 9px; margin-bottom: 5px; padding: 8px; border: 1px solid #ddd1b9; border-radius: 14px; background: white; text-align: left; } +.shared-book .book-cover { width: 64px; height: 85px; } +.shared-book strong, .shared-book small, .shared-book b { display: block; } +.shared-book strong { font-size: 10px; }.shared-book small { margin: 5px 0; color: var(--muted); font-size: 8px; }.shared-book b { color: var(--price); font: 700 13px Georgia, serif; } +.trade-tip { margin: 20px 0 12px; text-align: center; color: #858273; font-size: 8px; } +.chat-composer { position: absolute; z-index: 10; left: 10px; right: 10px; bottom: max(8px, env(safe-area-inset-bottom)); min-height: 62px; display: grid; grid-template-columns: 38px 38px 1fr auto; align-items: center; gap: 6px; padding: 7px; border: 1px solid var(--border); border-radius: 20px; background: rgba(255,253,248,.96); box-shadow: 0 10px 30px rgba(55,59,45,.18); } +.chat-composer > button:not(.send-button) { width: 38px; height: 38px; display: grid; place-items: center; border: 1px solid #ded4be; border-radius: 12px; background: transparent; color: var(--olive); } +.chat-composer svg { width: 19px; } +.chat-composer input { min-width: 0; height: 42px; padding: 0 11px; border: 1px solid #dfd4bd; border-radius: 13px; outline: none; background: #fbf9f2; font-size: 11px; } +.send-button { height: 42px; padding: 0 14px; border: 0; border-radius: 13px; background: var(--sage); color: white; } + +/* Profile and management */ +.profile-hero { display: grid; grid-template-columns: auto 1fr auto; gap: 13px; align-items: center; padding: 19px 15px; border: 1px solid rgba(213,199,167,.7); border-radius: 23px; background: linear-gradient(130deg, rgba(255,253,248,.92), rgba(230,235,215,.88)); box-shadow: var(--shadow); } +.profile-hero h1 { display: flex; align-items: center; gap: 6px; margin: 0; font: 700 20px "Noto Serif SC", serif; } +.profile-hero h1 svg { width: 18px; color: var(--sage); } +.profile-hero p { margin: 5px 0; color: #6e735f; font-size: 9px; } +.profile-hero span { color: var(--muted); font-size: 9px; } +.profile-hero > button { align-self: start; width: 37px; height: 37px; display: grid; place-items: center; border: 0; background: transparent; color: #777a6e; } +.profile-stats { display: grid; grid-template-columns: repeat(3, 1fr); margin: 12px 0; border: 1px solid rgba(213,199,167,.6); border-radius: 19px; background: rgba(255,253,248,.82); } +.profile-stats button { min-height: 71px; display: flex; flex-direction: column; align-items: center; justify-content: center; border: 0; border-right: 1px dashed #ddd2b9; background: transparent; } +.profile-stats button:last-child { border-right: 0; } +.profile-stats strong { color: var(--olive); font: 700 19px Georgia, serif; } +.profile-stats span { margin-top: 4px; color: var(--muted); font-size: 9px; } +.profile-menu { margin-top: 12px; padding: 13px; border: 1px solid rgba(213,199,167,.6); border-radius: 19px; background: rgba(255,253,248,.84); } +.profile-menu h2 { margin: 0 0 7px; color: var(--olive); font: 700 14px "Noto Serif SC", serif; } +.profile-menu > button { width: 100%; min-height: 62px; display: grid; grid-template-columns: 38px 1fr auto; align-items: center; gap: 10px; padding: 8px 0; border: 0; border-top: 1px dashed #e1d8c3; background: transparent; text-align: left; } +.profile-menu > button > span { width: 36px; height: 36px; display: grid; place-items: center; border-radius: 11px; background: #eef0e4; color: var(--sage); } +.profile-menu > button svg { width: 18px; } +.profile-menu strong, .profile-menu small { display: block; } +.profile-menu strong { font-size: 11px; }.profile-menu small { margin-top: 4px; color: var(--muted); font-size: 8px; } +.profile-menu button.danger { color: #a65f54; } +.profile-menu button.danger > span { background: #fff0ec; color: #b75f54; } +.profile-tobby { position: relative; min-height: 100px; display: flex; align-items: center; justify-content: flex-end; margin-top: 12px; padding-right: 20px; color: #777a6b; font-size: 10px; } +.profile-tobby img { position: absolute; width: 125px; height: 125px; object-fit: contain; left: 2px; bottom: -10px; } +.status-tabs { display: flex; gap: 7px; margin-bottom: 12px; } +.status-tabs button { flex: 1; min-height: 38px; border: 1px solid #ded4bd; border-radius: 12px; background: #fbf9f1; font-size: 10px; } +.status-tabs button.active { border-color: var(--sage); background: var(--sage); color: white; } +.manage-listing { display: grid; gap: 6px; margin-bottom: 12px; } +.manage-listing > .secondary-button { width: 100%; } +.floating-add { width: 150px; min-height: 45px; display: flex; align-items: center; justify-content: center; gap: 6px; margin: 18px auto; border: 1px solid var(--sage); border-radius: 15px; background: var(--sage); color: white; } +.floating-add svg { width: 18px; } + +/* State screens */ +.full-state { min-height: 100dvh; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 35px 26px; text-align: center; background: var(--cream); } +.full-state > .brand { position: absolute; left: 24px; top: max(24px, env(safe-area-inset-top)); } +.state-orbit { position: absolute; width: 300px; height: 300px; border: 1px dashed rgba(111,121,86,.22); border-radius: 50%; } +.full-state > img { position: relative; width: 260px; height: 260px; object-fit: contain; filter: drop-shadow(0 18px 18px rgba(70,72,56,.12)); } +.full-state h1 { position: relative; margin: -12px 0 8px; color: var(--olive); font: 700 25px "Noto Serif SC", serif; } +.full-state p { position: relative; max-width: 290px; margin: 0; color: var(--muted); font-size: 12px; line-height: 1.8; } +.full-state > .primary-button { position: relative; width: 210px; margin-top: 24px; } +.full-state > small { position: absolute; bottom: 25px; color: #9b978c; font-size: 8px; } +.states-index .state-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; } +.state-grid button { min-height: 142px; display: grid; grid-template-columns: 1fr auto; align-items: end; position: relative; overflow: hidden; padding: 10px; border: 1px solid rgba(213,199,167,.65); border-radius: 18px; background: rgba(255,253,248,.86); text-align: left; } +.state-grid img { position: absolute; width: 115px; height: 115px; object-fit: contain; right: -12px; top: -9px; opacity: .88; } +.state-grid span { position: relative; z-index: 1; font: 700 11px "Noto Serif SC", serif; } +.state-grid svg { width: 16px; } + +/* Responsive and focus */ +button:focus-visible, a:focus-visible, input:focus-visible, textarea:focus-visible, select:focus-visible { outline: 3px solid rgba(120,216,198,.65); outline-offset: 2px; } +@media (max-width: 370px) { + .welcome-copy h1 { font-size: 31px; } + .welcome-tobby { margin-bottom: -34px; } + .listing-main { grid-template-columns: 100px 1fr; gap: 9px; } + .listing-main .book-cover { width: 100px; } + .ai-card { grid-template-columns: 1fr; } + .form-grid { grid-template-columns: 1fr; } +} + +@media (min-width: 431px) { + .app-stage { padding-block: 12px; } + .phone-shell { min-height: calc(100dvh - 24px); height: calc(100dvh - 24px); border-radius: 28px; } + .toast { bottom: 120px; } +} + +/* Visual refinement pass: emblems, hierarchy and motion */ +body { -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; } +.route-view { width: 100%; max-width: 430px; min-width: 0; height: 100dvh; position: relative; } +.route-view > .phone-shell { width: 100%; } +.content-scroll { scroll-behavior: smooth; } + +.brand-mark { filter: drop-shadow(0 2px 1px rgba(79,89,64,.14)); } +.brand-mark i { position: relative; border: 1px solid rgba(200,174,114,.42); background: linear-gradient(150deg, #788360, #4f5940); } +.brand-mark i::before { content: ''; position: absolute; width: 1px; height: 15px; right: 4px; top: 4px; background: rgba(255,253,248,.42); transform: rotate(-8deg); } +.brand-mark i + i::before { left: 4px; right: auto; transform: rotate(8deg); } +.brand-mark i::after { content: ''; position: absolute; width: 4px; height: 7px; left: 5px; top: 7px; border: 1px solid rgba(255,253,248,.68); border-radius: 100% 0 100% 0; transform: rotate(-32deg); } +.brand-mark i + i::after { left: auto; right: 5px; transform: rotate(32deg) scaleX(-1); } +.brand-mark::before { content: ''; position: absolute; z-index: 2; left: 15px; bottom: 1px; width: 1px; height: 23px; background: rgba(255,253,248,.7); } +.brand-mark::after { content: '✦'; position: absolute; z-index: 3; left: 12px; top: 7px; color: #f2e9c8; font-size: 7px; } + +.topbar::after { content: ''; position: absolute; left: 20px; right: 20px; bottom: 0; height: 1px; background: linear-gradient(90deg, transparent, rgba(213,199,167,.72), transparent); } +.page-topbar { grid-template-columns: minmax(118px, 1fr) auto minmax(86px, 1fr); } +.page-topbar .brand > span:last-child { display: inline; } +.page-topbar .brand { gap: 5px; font-size: 18px; } +.page-topbar .brand-mark { transform: scale(.82); transform-origin: left center; margin-right: -5px; } +.leaf-action { width: 38px !important; height: 38px !important; border: 1px solid rgba(213,199,167,.78) !important; border-radius: 12px; background: linear-gradient(145deg, rgba(255,253,248,.95), rgba(238,240,226,.9)) !important; color: var(--sage) !important; box-shadow: inset 0 0 0 3px rgba(255,255,255,.55); } +.leaf-action svg { width: 18px; } + +.hero-card::after { content: '❧'; position: absolute; right: 13px; top: 11px; color: rgba(111,121,86,.38); font-size: 18px; transform: rotate(18deg); } +.guide-card { position: relative; overflow: hidden; } +.guide-card::before { content: '❧'; position: absolute; right: 13px; top: 10px; color: rgba(111,121,86,.48); font-size: 17px; transform: rotate(16deg); } +.guide-card::after { content: ''; position: absolute; inset: 7px; pointer-events: none; border: 1px dashed rgba(200,174,114,.42); border-radius: 19px; } +.welcome-steps::before, .welcome-steps::after { position: absolute; color: rgba(111,121,86,.42); font-size: 15px; } +.welcome-steps::before { content: '❧'; left: 10px; top: 8px; } +.welcome-steps::after { content: '❧'; right: 10px; bottom: 8px; transform: rotate(180deg); } +.profile-hero, .profile-menu, .upload-card { position: relative; overflow: hidden; } +.profile-hero::after, .profile-menu::after, .upload-card::before { content: '❧'; position: absolute; color: rgba(111,121,86,.28); font-size: 20px; pointer-events: none; } +.profile-hero::after { right: 12px; bottom: 6px; transform: rotate(-16deg); } +.profile-menu::after { right: 13px; top: 8px; } +.upload-card::before { right: 11px; top: 9px; transform: rotate(20deg); } + +.bottom-nav { border-color: rgba(200,174,114,.72); box-shadow: inset 0 0 0 3px rgba(255,255,255,.72), 0 12px 32px rgba(64,67,53,.18); } +.nav-item { z-index: 1; } +.nav-item.active:not(.publish)::before { content: ''; position: absolute; z-index: -1; width: 38px; height: 38px; top: -2px; border: 1px solid rgba(111,121,86,.42); border-radius: 50%; background: linear-gradient(145deg, #eef1e3, #dde3ce); box-shadow: 0 5px 12px rgba(79,89,64,.12), inset 0 0 0 3px rgba(255,255,255,.55); } +.nav-item.publish::after { content: '✦'; position: absolute; right: 6px; top: -10px; color: var(--gold); font-size: 13px; text-shadow: -42px 25px 0 rgba(200,174,114,.45); } + +.quick-filters { align-items: center; } +.quick-filters .availability-filter { gap: 7px; } +.availability-filter i { width: 28px; height: 17px; padding: 2px; border-radius: 999px; background: #d8d5ca; transition: background .2s ease; } +.availability-filter i::after { content: ''; display: block; width: 13px; height: 13px; border-radius: 50%; background: white; box-shadow: 0 1px 4px rgba(0,0,0,.18); transition: transform .22s cubic-bezier(.2,.8,.2,1); } +.availability-filter.active { border-color: rgba(111,121,86,.78); color: var(--olive); background: #edf0e3; } +.availability-filter.active i { background: var(--sage); } +.availability-filter.active i::after { transform: translateX(11px); } +.search-tobby-hint { min-height: 54px; display: flex; align-items: center; justify-content: flex-end; gap: 3px; margin: -2px 2px 5px; } +.search-tobby-hint img { width: 65px; height: 58px; object-fit: contain; filter: drop-shadow(0 5px 5px rgba(69,71,53,.1)); } +.search-tobby-hint span { position: relative; max-width: 205px; padding: 8px 11px; border: 1px solid rgba(213,199,167,.78); border-radius: 14px 14px 14px 5px; background: rgba(255,253,248,.9); color: #74766a; font-size: 9px; line-height: 1.5; box-shadow: 0 5px 14px rgba(82,78,59,.05); } +.search-tobby-hint strong { display: block; color: var(--olive); font-size: 10px; } + +.publish-page .content-scroll { display: flex; flex-direction: column; } +.publish-page .publish-actions { margin-top: auto; } +.upload-card { min-height: 244px; } +.tobby-tip { position: relative; z-index: 1; min-height: 112px; margin-top: 8px; } +.tobby-tip img { width: 126px; height: 110px; margin-left: -7px; filter: drop-shadow(0 8px 8px rgba(69,71,53,.12)); } +.tobby-tip span { margin-left: -10px; padding: 10px 13px; font-size: 10px; box-shadow: 0 6px 14px rgba(82,78,59,.05); } +.ai-card { box-shadow: inset 0 0 0 3px rgba(255,255,255,.45), 0 8px 20px rgba(79,89,64,.06); } +.stepper .active span { box-shadow: 0 4px 10px rgba(79,89,64,.18), inset 0 0 0 2px rgba(255,255,255,.2); } + +.profile-copy { min-width: 0; } +.profile-copy h1 { margin-bottom: 6px; } +.profile-badges { display: flex; align-items: center; flex-wrap: wrap; gap: 5px; } +.profile-badges span { display: inline-flex; align-items: center; gap: 3px; padding: 4px 7px; border-radius: 999px; background: #e5ead6; color: var(--olive); font-size: 8px; font-weight: 700; } +.profile-badges span + span { border: 1px solid #d8cfb5; background: rgba(255,253,248,.8); } +.profile-badges svg { width: 11px; height: 11px; } +.profile-copy p { margin: 7px 0 4px; } +.profile-copy small { display: block; overflow: hidden; color: var(--muted); font-size: 9px; text-overflow: ellipsis; white-space: nowrap; } +.profile-reminder { min-height: 76px; display: grid; grid-template-columns: 78px 1fr auto; align-items: center; gap: 5px; position: relative; overflow: hidden; margin: 12px 0; padding: 8px 10px 8px 4px; border: 1px solid rgba(213,199,167,.7); border-radius: 18px; background: rgba(255,253,248,.86); box-shadow: 0 7px 18px rgba(70,71,54,.05); } +.profile-reminder img { width: 86px; height: 86px; object-fit: contain; align-self: end; margin-bottom: -10px; } +.profile-reminder p { margin: 0; color: #6f7265; font-size: 9px; line-height: 1.55; } +.profile-reminder p strong { color: var(--olive); } +.profile-reminder button { min-height: 36px; display: flex; align-items: center; gap: 1px; padding: 0 9px; border: 1px solid var(--sage); border-radius: 12px; background: #edf0e3; color: var(--olive); font-size: 9px; } +.profile-reminder button svg { width: 13px; } + +@media (prefers-reduced-motion: no-preference) { + .route-view { animation: route-in .26s cubic-bezier(.2,.72,.24,1) both; } + .toast { animation: toast-pop .28s cubic-bezier(.18,.89,.32,1.22) both; } + .sheet-layer { animation: fade-in .18s ease-out both; } + .filter-sheet { animation: sheet-rise .28s cubic-bezier(.2,.78,.2,1) both; } + .guide-card, .onboarding-panel > img { animation: guide-in .32s cubic-bezier(.2,.78,.2,1) both; } + .listing-card, .thread-list > button, .notification-grid > button { animation: card-rise .3s cubic-bezier(.2,.72,.24,1) both; } + .listing-stack > :nth-child(2), .thread-list > :nth-child(2), .notification-grid > :nth-child(2) { animation-delay: 35ms; } + .listing-stack > :nth-child(3), .thread-list > :nth-child(3), .notification-grid > :nth-child(3) { animation-delay: 70ms; } + .listing-stack > :nth-child(4), .thread-list > :nth-child(4), .notification-grid > :nth-child(4) { animation-delay: 105ms; } + .message-row { animation: message-in .24s cubic-bezier(.2,.72,.24,1) both; } + .publish-page .upload-card, .publish-page .ai-card, .publish-page .form-card, .publish-page .publish-preview { animation: card-rise .28s ease-out both; } + .nav-item.publish::after { animation: sparkle 2.4s ease-in-out infinite; } + .search-tobby-hint img { animation: hint-float 3.6s ease-in-out infinite; } + button:not(.nav-item), .listing-card, .thread-list > button, .profile-menu > button, .book-tile { transition: transform .18s cubic-bezier(.2,.72,.24,1), border-color .18s ease, background-color .18s ease, box-shadow .18s ease; } + button:not(.nav-item):active, .profile-menu > button:active, .thread-list > button:active { transform: scale(.975); } + .nav-item { transition: color .2s ease, transform .2s cubic-bezier(.2,.72,.24,1); } + .nav-item:active { transform: translateY(1px) scale(.96); } + .nav-item.publish:active { transform: translateY(-8px) scale(.96); } + .form-field input, .form-field select, .form-field textarea, .chat-composer input { transition: border-color .18s ease, box-shadow .18s ease, background-color .18s ease; } +} + +@keyframes route-in { from { opacity: 0; transform: translateY(7px) scale(.995); } to { opacity: 1; transform: none; } } +@keyframes toast-pop { from { opacity: 0; transform: translate(-50%, 14px) scale(.94); } to { opacity: 1; transform: translate(-50%, 0) scale(1); } } +@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } } +@keyframes sheet-rise { from { transform: translateY(34px); opacity: .65; } to { transform: none; opacity: 1; } } +@keyframes guide-in { from { transform: translateY(14px) scale(.97); opacity: 0; } to { transform: none; opacity: 1; } } +@keyframes card-rise { from { transform: translateY(8px); opacity: 0; } to { transform: none; opacity: 1; } } +@keyframes message-in { from { transform: translateY(6px); opacity: 0; } to { transform: none; opacity: 1; } } +@keyframes sparkle { 0%, 100% { opacity: .45; transform: scale(.85) rotate(0); } 50% { opacity: 1; transform: scale(1.1) rotate(12deg); } } +@keyframes hint-float { 0%, 100% { transform: translateY(1px) rotate(-1deg); } 50% { transform: translateY(-3px) rotate(1deg); } } + +@media (hover: hover) and (pointer: fine) { + .book-tile:hover, .listing-card:hover, .thread-list > button:hover { transform: translateY(-2px); border-color: rgba(111,121,86,.52); box-shadow: 0 12px 25px rgba(70,71,54,.1); } + .primary-button:hover, .hero-button:hover { box-shadow: 0 11px 24px rgba(79,89,64,.28); } +} + +@media (max-width: 370px) { + .page-topbar { grid-template-columns: minmax(103px, 1fr) auto minmax(78px, 1fr); padding-left: 14px; padding-right: 14px; } + .page-topbar .brand { font-size: 16px; } + .page-topbar .brand-mark { transform: scale(.74); margin-right: -7px; } + .page-topbar h1 { font-size: 18px; } + .search-tobby-hint { justify-content: center; } + .search-tobby-hint img { width: 56px; } + .profile-reminder { grid-template-columns: 68px 1fr; } + .profile-reminder button { grid-column: 2; justify-self: start; margin-top: -7px; } +} + +@media (min-width: 431px) { + .route-view { height: calc(100dvh - 24px); } +} + +/* Resource bootstrap, readability and interaction completion */ +.boot-screen { min-height: 100dvh; overflow: hidden; display: flex; flex-direction: column; align-items: center; padding: max(28px, env(safe-area-inset-top)) 26px 28px; background: linear-gradient(155deg, rgba(255,253,248,.96), rgba(240,239,225,.96)), url('./assets/paper-bg.webp') center / cover; } +.boot-screen > *:not(.paper-texture) { position: relative; z-index: 1; } +.boot-brand { width: 100%; display: flex; align-items: center; justify-content: space-between; } +.boot-brand > span { color: #8b8b7f; font-size: 11px; letter-spacing: .08em; } +.boot-visual { width: 292px; height: 318px; display: grid; place-items: center; position: relative; margin: 23px 0 -8px; } +.boot-visual::before, .boot-visual::after, .boot-visual > i { content: ''; position: absolute; border-radius: 50%; } +.boot-visual::before { inset: 12px; border: 1px dashed rgba(111,121,86,.34); animation: boot-orbit 11s linear infinite; } +.boot-visual::after { inset: 43px; background: radial-gradient(circle, rgba(174,182,154,.42), rgba(247,244,234,.08) 68%, transparent 70%); box-shadow: 0 24px 55px rgba(79,89,64,.12); } +.boot-visual > i { width: 10px; height: 10px; top: 16px; left: 50%; background: var(--gold); box-shadow: 128px 132px 0 var(--aqua), -130px 156px 0 rgba(111,121,86,.6); } +.boot-visual img { z-index: 2; width: 278px; height: 278px; object-fit: contain; filter: drop-shadow(0 18px 17px rgba(67,70,53,.16)); animation: boot-tobby 2.8s ease-in-out infinite; } +.boot-copy { width: 100%; text-align: center; } +.boot-copy p { margin: 0 0 8px; color: var(--gold); font: 700 10px Georgia, serif; letter-spacing: .18em; } +.boot-copy h1 { margin: 0; color: var(--olive); font: 700 23px/1.48 "Noto Serif SC", "Songti SC", serif; } +.boot-copy > span { display: block; margin-top: 9px; color: var(--muted); font-size: 12px; } +.boot-progress { width: 100%; height: 10px; overflow: hidden; margin-top: 25px; border: 1px solid rgba(213,199,167,.8); border-radius: 999px; background: rgba(255,253,248,.72); box-shadow: inset 0 2px 5px rgba(79,89,64,.08); } +.boot-progress i { display: block; height: 100%; border-radius: inherit; background: linear-gradient(90deg, var(--sage), var(--aqua), #e3cf96); transition: width .22s ease; } +.boot-status { width: 100%; display: flex; justify-content: space-between; margin-top: 8px; color: #74776a; font-size: 11px; } +.boot-status strong { color: var(--olive); font: 700 12px Georgia, serif; } +.boot-screen > small { margin-top: auto; color: #939185; font-size: 10px; } + +.welcome-tobby { mix-blend-mode: normal; -webkit-mask-image: none; mask-image: none; } + +.section-more { min-height: 36px; display: inline-flex; align-items: center; gap: 3px; padding: 0 11px 0 13px; border: 1px solid rgba(111,121,86,.5); border-radius: 999px; background: linear-gradient(145deg, rgba(255,253,248,.95), rgba(235,239,223,.9)); color: var(--olive); box-shadow: 0 5px 13px rgba(79,89,64,.08), inset 0 0 0 2px rgba(255,255,255,.55); font-size: 11px; font-weight: 700; } +.section-more svg { width: 15px; height: 15px; } + +.ranking-card { padding: 14px; } +.rank-item { width: 100%; min-height: 82px; display: grid; grid-template-columns: 34px 49px minmax(0,1fr) auto 14px; gap: 9px; align-items: center; margin: 0; padding: 8px 8px 8px 5px; border: 1px solid rgba(213,199,167,.58); border-radius: 15px; background: linear-gradient(100deg, rgba(255,253,248,.9), rgba(244,244,233,.82)); text-align: left; box-shadow: 0 5px 12px rgba(75,75,58,.045); } +.rank-item + .rank-item { margin-top: 8px; } +.rank-number { width: 30px; height: 30px; display: grid; place-items: center; border: 1px solid rgba(200,174,114,.7); border-radius: 50%; background: #fffaf0; color: #aa8843; font: italic 700 13px Georgia, serif; } +.ranking-card .rank-item .book-cover { width: 49px; height: 64px; padding: 5px; border-radius: 6px 9px 9px 6px; } +.ranking-card .rank-item .book-cover .cover-leaf { margin: 0 0 3px; font-size: 13px; } +.ranking-card .rank-item .book-cover strong { display: -webkit-box; overflow: hidden; font-size: 7px; line-height: 1.25; white-space: normal; -webkit-box-orient: vertical; -webkit-line-clamp: 3; } +.rank-copy { min-width: 0; } +.rank-copy strong, .rank-copy small, .rank-copy em { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.rank-copy strong { color: var(--text); font-size: 13px; } +.rank-copy small { margin-top: 4px; color: var(--muted); font-size: 10px; } +.rank-copy em { margin-top: 5px; color: #7c826e; font-size: 9px; font-style: normal; } +.rank-price { text-align: right; } +.rank-price b, .rank-price small { display: block; } +.rank-price b { color: var(--price); font: 700 15px Georgia, serif; } +.rank-price small { margin-top: 5px; color: #8b8c80; font-size: 8px; } +.rank-item > svg { width: 14px; color: #9b9a8e; } + +.nav-item.publish { justify-content: center; gap: 1px; padding-top: 3px; } +.nav-item.publish > span { font-size: 9px; line-height: 1; transform: translateY(-2px); } + +.notification-grid > button { padding-right: 24px; } +.notification-grid > button small { display: block; margin-top: 6px; color: var(--sage); font-size: 9px; font-weight: 700; } +.notice-chevron { position: absolute; right: 7px; bottom: 8px; width: 14px; color: #97988b; } +.notification-detail-hero { min-height: 118px; display: grid; grid-template-columns: 58px 1fr auto; align-items: center; gap: 12px; position: relative; overflow: hidden; padding: 17px; border: 1px solid rgba(213,199,167,.68); border-radius: 22px; background: linear-gradient(125deg, rgba(255,253,248,.95), rgba(235,239,222,.9)); box-shadow: var(--shadow); } +.notification-detail-hero::after { content: '❧'; position: absolute; right: 13px; bottom: 3px; color: rgba(111,121,86,.24); font-size: 30px; transform: rotate(-16deg); } +.notification-detail-hero .notice-icon { width: 56px; height: 56px; } +.notification-detail-hero p { margin: 0; color: var(--gold); font-size: 9px; font-weight: 700; letter-spacing: .12em; } +.notification-detail-hero h1 { margin: 3px 0 4px; color: var(--olive); font: 700 21px "Noto Serif SC", serif; } +.notification-detail-hero div > span { color: var(--muted); font-size: 11px; } +.notification-detail-hero > b { align-self: start; position: relative; z-index: 1; padding: 5px 8px; border-radius: 999px; background: var(--sage); color: white; font-size: 9px; } +.notification-feed { display: grid; gap: 9px; margin-top: 14px; } +.notification-feed > button { width: 100%; min-height: 96px; display: grid; grid-template-columns: 35px 1fr 17px; align-items: center; gap: 10px; padding: 13px; border: 1px solid rgba(213,199,167,.62); border-radius: 17px; background: rgba(255,253,248,.88); text-align: left; box-shadow: 0 6px 15px rgba(73,72,56,.05); } +.feed-index { width: 32px; height: 32px; display: grid; place-items: center; border-radius: 50%; background: #edf0e3; color: var(--sage); font: 700 11px Georgia, serif; } +.notification-feed strong { font-size: 13px; } +.notification-feed p { margin: 5px 0; color: #686b60; font-size: 11px; line-height: 1.6; } +.notification-feed time { color: #96948a; font-size: 9px; } +.notification-feed svg { width: 16px; color: #96988b; } +.notification-safe { display: flex; align-items: center; gap: 6px; margin: 14px 2px; padding: 11px 12px; border-radius: 14px; background: #edf0e3; color: #656c59; font-size: 10px; line-height: 1.5; } +.notification-safe svg { width: 16px; flex: 0 0 auto; } + +/* Keep key reading sizes comfortably above the former 8–9px range. */ +.eyebrow { font-size: 11px; } +.hero-copy > p:not(.eyebrow) { font-size: 12.5px; } +.section-title h2 { font-size: 19px; } +.section-title a, .section-title > span { font-size: 12.5px; } +.book-cover small { font-size: 8.5px; } +.book-tile h3 { font-size: 13.5px; } +.book-tile > p { font-size: 11px; } +.book-meta span, .results-heading span { font-size: 10px; } +.nav-item { font-size: 11px; } +.welcome-copy > span { font-size: 13px; } +.welcome-copy p { font-size: 14px; } +.welcome-steps span { font-size: 9.5px; } +.welcome-actions p { font-size: 11px; } +.guide-card p { font-size: 13px; } +.guide-pills span { font-size: 10px; } +.search-tobby-hint span { font-size: 10.5px; } +.search-tobby-hint strong { font-size: 11.5px; } +.quick-filters button { font-size: 11px; } +.listing-copy > p { font-size: 11px; } +.listing-price del, .listing-price span, .listing-detail, .seller-line { font-size: 10px; } +.listing-actions button { font-size: 11px; } +.status-badge, .status-pill { font-size: 9px; } +.inline-state p { font-size: 12px; } +.sheet-title button, .filter-group button { font-size: 11px; } +.range-label, .filter-group > strong, .switch-row { font-size: 12.5px; } +.detail-title p, .detail-price del, .description-block p { font-size: 12px; } +.detail-price span, .detail-facts span, .description-block span, .seller-card p, .safety-note, .detail-cta > button:first-child { font-size: 10.5px; } +.seller-card span { font-size: 9.5px; } +.stepper p { font-size: 10px; } +.add-image span, .ai-card span { font-size: 9.5px; } +.ai-card button { font-size: 10px; } +.form-field, .form-field input, .form-field select, .form-field textarea { font-size: 12px; } +.tag-picker > span, .tag-picker button, .form-error { font-size: 10px; } +.notification-grid strong { font-size: 14px; } +.notification-grid p { font-size: 10px; line-height: 1.45; } +.thread-list h3 { font-size: 14px; } +.thread-list h3 span, .thread-list time, .thread-list b { font-size: 9px; } +.thread-list p { font-size: 11px; } +.tobby-banner span, .chat-user, .chat-safety { font-size: 10.5px; } +.message-row p { font-size: 12px; } +.message-row time, .trade-tip { font-size: 9px; } +.chat-composer input { font-size: 12px; } +.profile-hero p, .profile-hero span, .profile-copy small, .profile-stats span, .profile-menu small, .profile-reminder p, .profile-reminder button { font-size: 10px; } +.profile-menu strong { font-size: 12px; } +.state-grid span { font-size: 12px; } +.full-state > small { font-size: 9px; } + +/* Final readability lift: secondary copy remains compact, but never hairline-small on a phone. */ +.hero-copy > p:not(.eyebrow) { font-size: 13.5px; } +.book-tile h3 { font-size: 14px; } +.book-tile > p { font-size: 12px; } +.book-meta span, .results-heading span { font-size: 11px; } +.nav-item { font-size: 12px; } +.ranking-card .rank-item { min-height: 86px; } +.rank-copy strong { font-size: 14px; } +.rank-copy small { font-size: 11px; } +.rank-copy em { font-size: 10px; } +.rank-price small { font-size: 9px; } +.notification-grid strong { font-size: 15px; } +.notification-grid p { font-size: 11px; } +.notification-grid > button small { font-size: 10px; } +.thread-list p { font-size: 12px; } +.thread-list h3 span, .thread-list time, .thread-list b { font-size: 10px; } +.notification-detail-hero div > span { font-size: 12px; } +.notification-feed strong { font-size: 14px; } +.notification-feed p { font-size: 12px; } +.notification-feed time { font-size: 10px; } +.notification-safe { font-size: 11px; } +.form-field, .form-field input, .form-field select, .form-field textarea { font-size: 13px; } +.profile-hero p, .profile-hero span, .profile-copy small, .profile-stats span, .profile-menu small, .profile-reminder p, .profile-reminder button { font-size: 11px; } +.profile-menu strong { font-size: 13px; } + +@keyframes boot-orbit { to { transform: rotate(360deg); } } +@keyframes boot-tobby { 0%, 100% { transform: translateY(3px); } 50% { transform: translateY(-5px); } } + +@media (max-width: 370px) { + .boot-screen { padding-left: 20px; padding-right: 20px; } + .boot-visual { width: 270px; height: 285px; margin-top: 16px; } + .boot-visual img { width: 250px; height: 250px; } + .boot-copy h1 { font-size: 21px; } + .ranking-card .rank-item { grid-template-columns: 31px 44px minmax(0,1fr) auto 12px; gap: 7px; } + .ranking-card .rank-item .book-cover { width: 44px; height: 60px; } + .rank-price small { display: none; } +} + +@media (prefers-reduced-motion: reduce) { + .boot-visual::before, .boot-visual img { animation: none; } + .boot-progress i { transition: none; } +} + +/* Tablet layout: retain the touch-first navigation while using the available canvas. */ +@media (min-width: 700px) { + .app-stage { padding: 16px; } + .route-view { width: 100%; max-width: 920px; height: calc(100dvh - 32px); } + .route-view > .phone-shell, + .phone-shell { width: 100%; height: 100%; min-height: 100%; border-radius: 28px; } + .topbar { height: 82px; padding: 17px 30px 11px; } + .content-scroll { height: calc(100% - 82px); padding: 12px 30px 116px; } + .bottom-nav { left: 26px; right: 26px; } + + .hero-card { min-height: 250px; } + .hero-copy { width: 58%; padding: 32px 0 28px 34px; } + .hero-copy h1 { font-size: 34px; } + .hero-tobby { width: 235px; height: 235px; right: 10px; bottom: -20px; } + .book-row { grid-auto-flow: initial; grid-template-columns: repeat(3, minmax(0, 1fr)); grid-auto-columns: initial; overflow: visible; } + .book-cover { height: 180px; } + .ranking-card { padding: 20px; } + + .listing-stack { grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: start; } + .listing-main { grid-template-columns: 104px minmax(0, 1fr); } + .listing-main .book-cover { width: 104px; height: 145px; } + .listing-actions { grid-template-columns: repeat(3, 1fr); } + + .detail-page .content-scroll { display: grid; grid-template-columns: minmax(280px, .9fr) minmax(340px, 1.1fr); grid-auto-rows: min-content; align-items: start; gap: 14px 18px; } + .detail-gallery { grid-column: 1; grid-row: 1 / span 4; min-height: 460px; } + .detail-gallery > .book-cover { height: 448px; } + .detail-card { grid-column: 2; margin-top: 0; } + .seller-card, .detail-page .safety-note, .detail-cta { grid-column: 2; margin: 0; } + .detail-cta { position: static; } + + .publish-page .content-scroll { width: min(100%, 780px); margin-inline: auto; } + .image-grid { grid-template-columns: repeat(4, 1fr); } + .form-card { padding: 22px; } + + .notification-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } + .notification-grid > button { min-height: 124px; } + .thread-list { grid-template-columns: repeat(2, minmax(0, 1fr)); } + .notification-feed { grid-template-columns: repeat(2, minmax(0, 1fr)); } + + .profile-page .content-scroll { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); align-content: start; gap: 14px; } + .profile-hero { grid-column: 1 / -1; } + .profile-stats, .profile-reminder, .profile-menu { margin: 0; } + .profile-stats, .profile-reminder { grid-column: 1 / -1; } + .profile-menu { height: 100%; } + .states-index .state-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } + + .welcome-page { display: grid; grid-template-columns: minmax(330px, .95fr) minmax(330px, 1.05fr); grid-template-rows: auto auto auto 1fr; column-gap: 38px; align-items: center; padding: 34px 48px; } + .welcome-brand { grid-column: 1 / -1; } + .welcome-copy { grid-column: 1; grid-row: 2; margin-top: 20px; } + .welcome-copy h1 { font-size: 44px; } + .welcome-tobby { grid-column: 2; grid-row: 2 / span 3; width: min(100%, 510px); margin: 0 auto; } + .welcome-steps { grid-column: 1; grid-row: 3; } + .welcome-actions { grid-column: 1; grid-row: 4; align-self: start; } + .full-state > img { width: 330px; height: 330px; } + .state-orbit { width: 380px; height: 380px; } +} + +/* Desktop layout: the former bottom bar becomes a persistent navigation rail. */ +@media (min-width: 1024px) { + .app-stage { padding: 24px; place-items: center; } + .route-view { max-width: 1320px; height: calc(100dvh - 48px); } + .phone-shell { border: 1px solid rgba(213,199,167,.72); border-radius: 30px; } + .topbar { height: 88px; padding: 20px 36px 12px; } + .topbar .brand { font-size: 28px; } + .content-scroll { height: calc(100% - 88px); padding: 18px 38px 38px 164px; overscroll-behavior: auto; } + + .bottom-nav { left: 26px; right: auto; top: 106px; bottom: 24px; width: 110px; height: auto; grid-template-columns: 1fr; grid-template-rows: repeat(5, minmax(66px, 1fr)); align-items: stretch; padding: 12px 9px; border-radius: 24px; } + .nav-item { min-height: 64px; justify-content: center; gap: 7px; border-radius: 17px !important; font-size: 13px; } + .nav-item svg { width: 22px; height: 22px; } + .nav-item.active:not(.publish) { background: #e8ecdc; } + .nav-item.active:not(.publish)::before { display: none; } + .nav-item.publish { transform: none; color: white; background: var(--sage); } + .nav-item.publish::before, .nav-item.publish::after { display: none; } + .nav-item.publish > span { font-size: 13px; transform: none; } + .nav-item.publish:active { transform: scale(.97); } + + .home-page .content-scroll { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(330px, .65fr); grid-auto-rows: min-content; gap: 14px 22px; } + .home-page .search-box, .home-page .category-chips { grid-column: 1 / -1; } + .home-page .category-chips { padding-top: 0; } + .home-page .hero-card { grid-column: 1; grid-row: 3; min-height: 285px; } + .home-page .ranking-card { grid-column: 2; grid-row: 3; align-self: stretch; margin: 0; } + .home-page .section-block { grid-column: 1 / -1; grid-row: 4; margin-top: 10px; } + .home-page .book-row { grid-template-columns: repeat(5, minmax(0, 1fr)); } + + .listing-stack { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; } + .listing-card { padding: 14px; } + .listing-main { grid-template-columns: 120px minmax(0, 1fr); } + .listing-main .book-cover { width: 120px; height: 160px; } + + .filter-sheet { width: 440px; height: 100%; max-height: none; margin-left: auto; padding: 22px 24px; border-radius: 26px 0 0 26px; } + .sheet-handle { display: none; } + + .detail-page .content-scroll { grid-template-columns: minmax(360px, .9fr) minmax(440px, 1.1fr); gap: 16px 24px; } + .detail-gallery { min-height: 540px; } + .detail-gallery > .book-cover { height: 528px; } + .detail-card { padding: 24px; } + .detail-title h1 { font-size: 28px; } + + .publish-page .content-scroll { width: min(100%, 920px); padding-left: 38px; } + .image-grid { grid-template-columns: repeat(6, 1fr); } + .form-card { gap: 16px; padding: 26px; } + .form-grid { gap: 16px; } + + .messages-page .notification-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px; } + .messages-page .thread-list { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px 14px; } + .notification-detail-page .notification-feed { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; } + + .profile-page .content-scroll { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; } + .profile-hero { padding: 24px; } + .profile-stats button { min-height: 92px; } + .profile-menu { padding: 18px; } + .profile-menu > button { min-height: 72px; } + + .simple-list-page .status-tabs { max-width: 620px; margin: 0 auto 18px; } + .simple-list-page > .content-scroll > .listing-stack, + .simple-list-page > .content-scroll { align-content: start; } + .states-index .state-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } + + .content-scroll.no-nav { width: min(100%, 900px); margin-inline: auto; padding: 18px 32px 100px; } + .chat-page .content-scroll { height: calc(100% - 88px); padding: 0 32px 98px; } + .chat-composer { width: min(calc(100% - 64px), 836px); left: 50%; right: auto; bottom: 22px; transform: translateX(-50%); } + .message-row > div { max-width: 62%; } + .toast { bottom: 38px; } + + .onboarding-panel { width: min(100%, 920px); margin-inline: auto; } + .onboarding-panel > img { width: 440px; max-height: 44vh; object-fit: contain; } + .guide-card { width: min(100%, 700px); margin-inline: auto; } + .boot-screen { padding-inline: max(40px, calc((100% - 620px) / 2)); } +} diff --git a/miniProgram/src/h5.css b/miniProgram/src/h5.css new file mode 100644 index 0000000..dd2f317 --- /dev/null +++ b/miniProgram/src/h5.css @@ -0,0 +1,11 @@ +/* Taro's router wrappers sit outside the Golden Reference app. Keep them + * layout-neutral so the original H5 DOM and CSS remain authoritative. */ +#app, .taro_router, .taro_page { + min-height: 100%; + font-size: 16px; + line-height: normal; +} + +[hidden] { + display: none !important; +} diff --git a/miniProgram/src/h5/GoldenRoute.tsx b/miniProgram/src/h5/GoldenRoute.tsx new file mode 100644 index 0000000..638a764 --- /dev/null +++ b/miniProgram/src/h5/GoldenRoute.tsx @@ -0,0 +1,30 @@ +import { useLayoutEffect } from 'react' +import { MobileApp } from '../../../web/app/components/mobile-app' + +function goldenPath() { + const url = new URL(globalThis.location.href) + const path = url.pathname + if (path === '/welcome') return '/' + if (path === '/search' || path === '/category') return `/category${url.search}` + if (path === '/books') return `/books/${url.searchParams.get('id') || 'math-7'}` + if (path === '/notifications') return `/messages/notifications/${url.searchParams.get('type') || 'system'}` + if (path === '/chat') return `/messages/${url.searchParams.get('id') || 'thread-lin'}` + if (path === '/states') { + const type = url.searchParams.get('type') + return !type || type === 'index' ? '/states' : `/states/${type === 'not-found' ? '404' : type}` + } + return path +} + +export default function GoldenRoute() { + useLayoutEffect(() => { + const resetScroll = () => { + globalThis.scrollTo(0, 0) + document.querySelectorAll('.taro_router, .taro_page, .content-scroll').forEach((element) => { element.scrollTop = 0 }) + } + resetScroll() + const frame = globalThis.requestAnimationFrame(resetScroll) + return () => globalThis.cancelAnimationFrame(frame) + }, []) + return +} diff --git a/miniProgram/src/h5/lucide-react.ts b/miniProgram/src/h5/lucide-react.ts new file mode 100644 index 0000000..347fd66 --- /dev/null +++ b/miniProgram/src/h5/lucide-react.ts @@ -0,0 +1,36 @@ +// Keep the Golden Reference import unchanged while avoiding lucide-react's +// all-icons barrel in Taro development builds. +export { default as ArrowLeft } from 'lucide-react/dist/esm/icons/arrow-left.mjs' +export { default as Bell } from 'lucide-react/dist/esm/icons/bell.mjs' +export { default as BookOpen } from 'lucide-react/dist/esm/icons/book-open.mjs' +export { default as Bookmark } from 'lucide-react/dist/esm/icons/bookmark.mjs' +export { default as Camera } from 'lucide-react/dist/esm/icons/camera.mjs' +export { default as Check } from 'lucide-react/dist/esm/icons/check.mjs' +export { default as ChevronDown } from 'lucide-react/dist/esm/icons/chevron-down.mjs' +export { default as ChevronRight } from 'lucide-react/dist/esm/icons/chevron-right.mjs' +export { default as CircleAlert } from 'lucide-react/dist/esm/icons/circle-alert.mjs' +export { default as Filter } from 'lucide-react/dist/esm/icons/filter.mjs' +export { default as Grid2X2 } from 'lucide-react/dist/esm/icons/grid-2x2.mjs' +export { default as Heart } from 'lucide-react/dist/esm/icons/heart.mjs' +export { default as Home } from 'lucide-react/dist/esm/icons/home.mjs' +export { default as ImagePlus } from 'lucide-react/dist/esm/icons/image-plus.mjs' +export { default as Info } from 'lucide-react/dist/esm/icons/info.mjs' +export { default as Leaf } from 'lucide-react/dist/esm/icons/leaf.mjs' +export { default as MapPin } from 'lucide-react/dist/esm/icons/map-pin.mjs' +export { default as MessageCircle } from 'lucide-react/dist/esm/icons/message-circle.mjs' +export { default as MoreHorizontal } from 'lucide-react/dist/esm/icons/more-horizontal.mjs' +export { default as PackageCheck } from 'lucide-react/dist/esm/icons/package-check.mjs' +export { default as Plus } from 'lucide-react/dist/esm/icons/plus.mjs' +export { default as RefreshCw } from 'lucide-react/dist/esm/icons/refresh-cw.mjs' +export { default as RotateCcw } from 'lucide-react/dist/esm/icons/rotate-ccw.mjs' +export { default as Search } from 'lucide-react/dist/esm/icons/search.mjs' +export { default as Send } from 'lucide-react/dist/esm/icons/send.mjs' +export { default as Settings } from 'lucide-react/dist/esm/icons/settings.mjs' +export { default as ShieldCheck } from 'lucide-react/dist/esm/icons/shield-check.mjs' +export { default as SlidersHorizontal } from 'lucide-react/dist/esm/icons/sliders-horizontal.mjs' +export { default as Sparkles } from 'lucide-react/dist/esm/icons/sparkles.mjs' +export { default as Star } from 'lucide-react/dist/esm/icons/star.mjs' +export { default as Trash2 } from 'lucide-react/dist/esm/icons/trash-2.mjs' +export { default as UserRound } from 'lucide-react/dist/esm/icons/user-round.mjs' +export { default as WandSparkles } from 'lucide-react/dist/esm/icons/wand-sparkles.mjs' +export { default as X } from 'lucide-react/dist/esm/icons/x.mjs' diff --git a/miniProgram/src/h5/next-image.tsx b/miniProgram/src/h5/next-image.tsx new file mode 100644 index 0000000..e377ff3 --- /dev/null +++ b/miniProgram/src/h5/next-image.tsx @@ -0,0 +1,10 @@ +import type { ImgHTMLAttributes } from 'react' + +type NextImageProps = ImgHTMLAttributes & { + priority?: boolean + unoptimized?: boolean +} + +export default function NextImage({ priority: _priority, unoptimized: _unoptimized, ...props }: NextImageProps) { + return +} diff --git a/miniProgram/src/hosting/_redirects b/miniProgram/src/hosting/_redirects new file mode 100644 index 0000000..7797f7c --- /dev/null +++ b/miniProgram/src/hosting/_redirects @@ -0,0 +1 @@ +/* /index.html 200 diff --git a/miniProgram/src/index.html b/miniProgram/src/index.html new file mode 100644 index 0000000..1bf83ea --- /dev/null +++ b/miniProgram/src/index.html @@ -0,0 +1,34 @@ + + + + + + + + + + + BITerStore · 让每一本书继续被需要 + + + + +
+ + diff --git a/miniProgram/src/pages/book-detail/index.tsx b/miniProgram/src/pages/book-detail/index.tsx deleted file mode 100644 index 4616085..0000000 --- a/miniProgram/src/pages/book-detail/index.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import { View } from '@tarojs/components' -import { AppShell } from '../../components/AppShell' -export default function BookDetailPage() { return 商品详情准备中 } diff --git a/miniProgram/src/pages/chat/index.config.ts b/miniProgram/src/pages/chat/index.config.ts new file mode 100644 index 0000000..4e65a39 --- /dev/null +++ b/miniProgram/src/pages/chat/index.config.ts @@ -0,0 +1 @@ +export default definePageConfig({ navigationStyle: 'custom' }) diff --git a/miniProgram/src/pages/chat/index.h5.tsx b/miniProgram/src/pages/chat/index.h5.tsx new file mode 100644 index 0000000..dd0f132 --- /dev/null +++ b/miniProgram/src/pages/chat/index.h5.tsx @@ -0,0 +1 @@ +export { default } from '@/h5/GoldenRoute' diff --git a/miniProgram/src/pages/chat/index.tsx b/miniProgram/src/pages/chat/index.tsx index 220a23f..5835a15 100644 --- a/miniProgram/src/pages/chat/index.tsx +++ b/miniProgram/src/pages/chat/index.tsx @@ -1,3 +1,28 @@ -import { View } from '@tarojs/components' -import { AppShell } from '../../components/AppShell' -export default function ChatPage() { return 聊天准备中 } +import { useCallback, useEffect, useState } from 'react' +import Taro from '@tarojs/taro' +import { Button, Input, Text, View } from '@tarojs/components' +import { AppShell, Avatar, BookCover } from '@/components/ui' +import { Glyph } from '@/components/Glyph' +import { demoRepository, getUser } from '@/domain/repository' +import { CURRENT_USER_ID, seedListings } from '@/domain/seed' +import type { ChatThread } from '@/domain/types' +import { mediaAdapter } from '@/platform' + +export default function ChatPage() { + const id = Taro.getCurrentInstance().router?.params.id || 'thread-lin' + const [thread, setThread] = useState() + const [text, setText] = useState('') + const load = useCallback(() => demoRepository.getThread(id).then(setThread), [id]) + useEffect(() => { void load() }, [load]) + const send = async () => { if (!text.trim()) return; await demoRepository.sendMessage(id, text.trim()); setText(''); await load() } + const sendImage = async () => { const files = await mediaAdapter.persist(await mediaAdapter.pick()); if (files[0]) { await demoRepository.sendMessage(id, '[图片]', files[0].id); await load() } } + const user = thread ? getUser(thread.participantId) : undefined + const listing = seedListings.find((item) => item.id === thread?.listingId) || seedListings[0] + return + {user && {user.campus}校区 · 在线} + 站内沟通更安全 · 当面交易请确认书况 + {thread?.messages.map((message) => { const mine = message.senderId === CURRENT_USER_ID; return {!mine && user && }{message.kind === 'listing' && }{message.text}{message.createdAt}{mine && } })} + ❧ 交易小贴士:请在校内当面交易,确认书况后再付款哦~ ❧ + setText(event.detail.value)} onConfirm={send} placeholder='输入消息…' /> + +} diff --git a/miniProgram/src/pages/favorites/index.config.ts b/miniProgram/src/pages/favorites/index.config.ts new file mode 100644 index 0000000..4e65a39 --- /dev/null +++ b/miniProgram/src/pages/favorites/index.config.ts @@ -0,0 +1 @@ +export default definePageConfig({ navigationStyle: 'custom' }) diff --git a/miniProgram/src/pages/favorites/index.h5.tsx b/miniProgram/src/pages/favorites/index.h5.tsx new file mode 100644 index 0000000..dd0f132 --- /dev/null +++ b/miniProgram/src/pages/favorites/index.h5.tsx @@ -0,0 +1 @@ +export { default } from '@/h5/GoldenRoute' diff --git a/miniProgram/src/pages/favorites/index.tsx b/miniProgram/src/pages/favorites/index.tsx index d15684d..3c3672f 100644 --- a/miniProgram/src/pages/favorites/index.tsx +++ b/miniProgram/src/pages/favorites/index.tsx @@ -1,3 +1,14 @@ -import { View } from '@tarojs/components' -import { AppShell } from '../../components/AppShell' -export default function FavoritesPage() { return 收藏准备中 } +import { useCallback, useState } from 'react' +import { Button, Image, Text, View } from '@tarojs/components' +import { useDidShow } from '@tarojs/taro' +import { AppShell, ListingCard } from '@/components/ui' +import { demoRepository } from '@/domain/repository' +import type { Listing } from '@/domain/types' +import { navigationAdapter } from '@/platform' + +export default function FavoritesPage() { + const [items, setItems] = useState() + const load = useCallback(() => demoRepository.listFavorites().then(setItems), []) + useDidShow(() => { void load() }) + return {items === undefined ? 托比正在翻找书架… : items.length ? {items.map((item) => { await demoRepository.toggleFavorite(item.id); setItems(items.filter((value) => value.id !== item.id)) }} onTap={() => navigationAdapter.go(`/pages/listing/detail?id=${item.id}`)} />)} : 收藏夹还空空的看到心仪的书,点一下爱心就能在这里找到它。} +} diff --git a/miniProgram/src/pages/home/index.config.ts b/miniProgram/src/pages/home/index.config.ts new file mode 100644 index 0000000..9411eb8 --- /dev/null +++ b/miniProgram/src/pages/home/index.config.ts @@ -0,0 +1 @@ +export default definePageConfig({ navigationStyle: 'custom', usingComponents: { 'custom-tab-bar': '../../custom-tab-bar/index' } }) diff --git a/miniProgram/src/pages/home/index.h5.tsx b/miniProgram/src/pages/home/index.h5.tsx new file mode 100644 index 0000000..dd0f132 --- /dev/null +++ b/miniProgram/src/pages/home/index.h5.tsx @@ -0,0 +1 @@ +export { default } from '@/h5/GoldenRoute' diff --git a/miniProgram/src/pages/home/index.tsx b/miniProgram/src/pages/home/index.tsx index 75ce8d4..99c0873 100644 --- a/miniProgram/src/pages/home/index.tsx +++ b/miniProgram/src/pages/home/index.tsx @@ -1,46 +1,27 @@ -import { Button, Image, ScrollView, Text, View } from '@tarojs/components' +import { useCallback, useState } from 'react' +import { Button, Image, Text, View } from '@tarojs/components' +import { useDidShow } from '@tarojs/taro' +import { AppShell, BookTile, RankItem } from '@/components/ui' +import { Glyph } from '@/components/Glyph' +import { demoRepository } from '@/domain/repository' +import { defaultFilters } from '@/domain/filters' +import type { Listing } from '@/domain/types' +import { navigationAdapter } from '@/platform' -import { assets } from '../../assets' -import { AppShell } from '../../components/AppShell' -import { BookCover, BookTile } from '../../components/BookCard' -import { Glyph } from '../../components/Glyph' -import { categories } from '../../domain/constants' -import { seedBooks } from '../../domain/demo-data' -import { navigationAdapter, routes } from '../../platform/navigation' +const categories = ['全部', '教材教辅', '专业课', '考研考公', '文学小说'] export default function HomePage() { - return ( - - navigationAdapter.to(routes.search)}> - 搜索书名、作者或 ISBN - - - {categories.map((category, index) => )} - - - - 书页轻翻 · 好物续航 - 以书会友{`\n`}共享知识之美 - 让每一本闲置书,遇见下一位需要它的人。 - - - - - - - 精选推荐 - {seedBooks.slice(0, 5).map((book) => )} - - - 校园热榜本周流动好书 - {seedBooks.slice(0, 3).map((book, index) => ( - navigationAdapter.to(routes.bookDetail, { id: book.id })} key={book.id}> - 0{index + 1} - {book.title}{book.author}{book.campus}校区 · {book.condition} - ¥{book.price}查看详情 - - ))} - - - ) + const [items, setItems] = useState([]) + const load = useCallback(() => demoRepository.listListings().then(setItems), []) + useDidShow(() => { void load() }) + const search = async () => { await demoRepository.saveFilters(defaultFilters); await navigationAdapter.switchTab('/pages/search/index') } + const open = (item: Listing) => navigationAdapter.go(`/pages/listing/detail?id=${item.id}`) + + return + + {categories.map((category, index) => )} + 书页轻翻 · 好物续航以书会友{process.env.TARO_ENV === 'h5' ? '\n' : ' '}共享知识之美让每一本闲置书,遇见下一位需要它的人。 + 精选推荐{items.slice(0, 5).map((item) => open(item)} />)} + 校园热榜本周流动好书{items.slice(0, 3).map((item, index) => open(item)} />)} + } diff --git a/miniProgram/src/pages/listing/detail.config.ts b/miniProgram/src/pages/listing/detail.config.ts new file mode 100644 index 0000000..4e65a39 --- /dev/null +++ b/miniProgram/src/pages/listing/detail.config.ts @@ -0,0 +1 @@ +export default definePageConfig({ navigationStyle: 'custom' }) diff --git a/miniProgram/src/pages/listing/detail.h5.tsx b/miniProgram/src/pages/listing/detail.h5.tsx new file mode 100644 index 0000000..dd0f132 --- /dev/null +++ b/miniProgram/src/pages/listing/detail.h5.tsx @@ -0,0 +1 @@ +export { default } from '@/h5/GoldenRoute' diff --git a/miniProgram/src/pages/listing/detail.tsx b/miniProgram/src/pages/listing/detail.tsx new file mode 100644 index 0000000..e42fcfa --- /dev/null +++ b/miniProgram/src/pages/listing/detail.tsx @@ -0,0 +1,27 @@ +import { useEffect, useState } from 'react' +import Taro from '@tarojs/taro' +import { Button, Text, View } from '@tarojs/components' +import { AppShell, Avatar, BookCover } from '@/components/ui' +import { Glyph } from '@/components/Glyph' +import { demoRepository, getUser } from '@/domain/repository' +import type { Listing } from '@/domain/types' +import { navigationAdapter } from '@/platform' + +export default function ListingDetailPage() { + const id = Taro.getCurrentInstance().router?.params.id || 'math-7' + const [item, setItem] = useState() + const [favorite, setFavorite] = useState(false) + useEffect(() => { void demoRepository.getListing(id).then(setItem).catch(() => navigationAdapter.go('/pages/states/index?type=not-found')) }, [id]) + if (!item) return 正在翻找这本书… + const seller = getUser(item.sellerId) + const contact = async () => { const thread = await demoRepository.ensureThread(item.id); await navigationAdapter.go(`/pages/chat/index?id=${thread}`) } + const unavailable = item.status !== 'available' + const label = { available: '可交易', sold: '已售', offline: '已下架', draft: '草稿' }[item.status] + return + {unavailable && {label}} + {label}{item.title}{item.author}¥{item.price.toFixed(2)}¥{item.originalPrice.toFixed(2)}{item.condition}⌖ {item.campus}校区▥ {item.course}ⓘ ISBN {item.isbn}书籍简介{item.description}{item.tags.map((tag) => #{tag})} + {seller.name} ◈{seller.campus}校区 · 已完成校园认证{seller.responseTime} + 建议在校内公共场所当面验书,确认书况后再付款。 + + +} diff --git a/miniProgram/src/pages/messages/index.config.ts b/miniProgram/src/pages/messages/index.config.ts new file mode 100644 index 0000000..9411eb8 --- /dev/null +++ b/miniProgram/src/pages/messages/index.config.ts @@ -0,0 +1 @@ +export default definePageConfig({ navigationStyle: 'custom', usingComponents: { 'custom-tab-bar': '../../custom-tab-bar/index' } }) diff --git a/miniProgram/src/pages/messages/index.h5.tsx b/miniProgram/src/pages/messages/index.h5.tsx new file mode 100644 index 0000000..dd0f132 --- /dev/null +++ b/miniProgram/src/pages/messages/index.h5.tsx @@ -0,0 +1 @@ +export { default } from '@/h5/GoldenRoute' diff --git a/miniProgram/src/pages/messages/index.tsx b/miniProgram/src/pages/messages/index.tsx index 52c37e4..546ccff 100644 --- a/miniProgram/src/pages/messages/index.tsx +++ b/miniProgram/src/pages/messages/index.tsx @@ -1,3 +1,23 @@ -import { View } from '@tarojs/components' -import { AppShell } from '../../components/AppShell' -export default function MessagesPage() { return 消息中心准备中 } +import { useCallback, useState } from 'react' +import { Button, Image, Text, View } from '@tarojs/components' +import { useDidShow } from '@tarojs/taro' +import { AppShell, Avatar } from '@/components/ui' +import { Glyph, type GlyphName } from '@/components/Glyph' +import { demoRepository, getUser } from '@/domain/repository' +import type { ChatThread, Notification } from '@/domain/types' +import { navigationAdapter } from '@/platform' + +const noticeGlyphs: Record = { like: 'heart', comment: 'message', system: 'bell', follow: 'user' } + +export default function MessagesPage() { + const [threads, setThreads] = useState([]) + const [notices, setNotices] = useState([]) + const load = useCallback(() => Promise.all([demoRepository.listThreads(), demoRepository.listNotifications()]).then(([a, b]) => { setThreads(a); setNotices(b) }), []) + useDidShow(() => { void load() }) + return + {notices.map((notice) => )} + 私聊消息✓ 全部已读 + {threads.map((thread) => { const user = getUser(thread.participantId); const last = thread.messages.at(-1); return })} + Tobby 提醒:及时回复消息,能提升成交率哦~ + +} diff --git a/miniProgram/src/pages/my-listings/index.config.ts b/miniProgram/src/pages/my-listings/index.config.ts new file mode 100644 index 0000000..4e65a39 --- /dev/null +++ b/miniProgram/src/pages/my-listings/index.config.ts @@ -0,0 +1 @@ +export default definePageConfig({ navigationStyle: 'custom' }) diff --git a/miniProgram/src/pages/my-listings/index.h5.tsx b/miniProgram/src/pages/my-listings/index.h5.tsx new file mode 100644 index 0000000..dd0f132 --- /dev/null +++ b/miniProgram/src/pages/my-listings/index.h5.tsx @@ -0,0 +1 @@ +export { default } from '@/h5/GoldenRoute' diff --git a/miniProgram/src/pages/my-listings/index.tsx b/miniProgram/src/pages/my-listings/index.tsx index 33e1087..a33152e 100644 --- a/miniProgram/src/pages/my-listings/index.tsx +++ b/miniProgram/src/pages/my-listings/index.tsx @@ -1,3 +1,17 @@ -import { View } from '@tarojs/components' -import { AppShell } from '../../components/AppShell' -export default function MyListingsPage() { return 发布管理准备中 } +import { useCallback, useMemo, useState } from 'react' +import { Button, Image, Text, View } from '@tarojs/components' +import { useDidShow } from '@tarojs/taro' +import { AppShell, ListingCard } from '@/components/ui' +import { demoRepository } from '@/domain/repository' +import type { Listing, ListingStatus } from '@/domain/types' +import { navigationAdapter } from '@/platform' + +export default function MyListingsPage() { + const [tab, setTab] = useState('all') + const [items, setItems] = useState([]) + const load = useCallback(() => demoRepository.listMyListings().then(setItems), []) + useDidShow(() => { void load() }) + const visible = useMemo(() => tab === 'all' ? items : items.filter((item) => item.status === tab), [items, tab]) + const change = async (item: Listing) => { await demoRepository.updateListingStatus(item.id, item.status === 'available' ? 'sold' : 'available'); await load() } + return {([['all', '全部'], ['available', '在售'], ['sold', '已售'], ['offline', '下架']] as const).map(([value, label]) => )}{visible.length ? visible.map((item) => navigationAdapter.go(`/pages/listing/detail?id=${item.id}`)} />) : 这次没有找到合适的书换个状态,或者发布一本闲置书吧。} +} diff --git a/miniProgram/src/pages/not-found/index.tsx b/miniProgram/src/pages/not-found/index.tsx deleted file mode 100644 index a19406f..0000000 --- a/miniProgram/src/pages/not-found/index.tsx +++ /dev/null @@ -1,2 +0,0 @@ -import { FullState } from '../../components/StateView' -export default function NotFoundPage() { return } diff --git a/miniProgram/src/pages/notification-detail/index.tsx b/miniProgram/src/pages/notification-detail/index.tsx deleted file mode 100644 index 298ed8d..0000000 --- a/miniProgram/src/pages/notification-detail/index.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import { View } from '@tarojs/components' -import { AppShell } from '../../components/AppShell' -export default function NotificationDetailPage() { return 消息详情准备中 } diff --git a/miniProgram/src/pages/notification/detail.config.ts b/miniProgram/src/pages/notification/detail.config.ts new file mode 100644 index 0000000..4e65a39 --- /dev/null +++ b/miniProgram/src/pages/notification/detail.config.ts @@ -0,0 +1 @@ +export default definePageConfig({ navigationStyle: 'custom' }) diff --git a/miniProgram/src/pages/notification/detail.h5.tsx b/miniProgram/src/pages/notification/detail.h5.tsx new file mode 100644 index 0000000..dd0f132 --- /dev/null +++ b/miniProgram/src/pages/notification/detail.h5.tsx @@ -0,0 +1 @@ +export { default } from '@/h5/GoldenRoute' diff --git a/miniProgram/src/pages/notification/detail.tsx b/miniProgram/src/pages/notification/detail.tsx new file mode 100644 index 0000000..e94399c --- /dev/null +++ b/miniProgram/src/pages/notification/detail.tsx @@ -0,0 +1,22 @@ +import Taro from '@tarojs/taro' +import { Button, Text, View } from '@tarojs/components' +import { AppShell } from '@/components/ui' +import { Glyph, type GlyphName } from '@/components/Glyph' +import type { Notification } from '@/domain/types' +import { seedNotifications } from '@/domain/seed' +import { navigationAdapter } from '@/platform' + +const details: Record> = { + like: [['林小暖', '赞了你发布的《高等数学(第七版)上册》。', '10:18', '/pages/listing/detail?id=math-7'], ['简一一', '赞了你的校园书单「期末复习好书」。', '昨天 18:42', '/pages/favorites/index'], ['Oliver_周', '赞了你分享的旧书循环动态。', '周五 20:06', '/pages/profile/index']], + comment: [['Oliver_周', '评论:书的笔记多吗?方便拍一下目录页吗?', '10:05', '/pages/listing/detail?id=data-c'], ['林小暖', '评论:这本高数正好是我需要的版本~', '昨天 21:30', '/pages/listing/detail?id=math-7'], ['Leo 学长', '评论:中关村校区也可以约时间自取。', '昨天 16:12', '/pages/chat/index?id=thread-leo'], ['简一一', '评论:谢谢你的书单推荐!', '周四 19:45', '/pages/chat/index?id=thread-jian'], ['Tobby', '你的发布收到了新的留言,记得及时回复。', '周三 12:08', '/pages/messages/index']], + system: [['校园交易安全提醒', '请尽量选择校内公共区域当面交易,确认书况后再付款。', '今天 09:00', '/pages/states/index?type=index'], ['BITerStore 试运行公告', '演示数据与状态体验入口已经更新完成。', '昨天 12:00', '/pages/profile/index']], + follow: [['简一一', '关注了你,之后发布的新书会更容易被她发现。', '昨天 15:26', '/pages/chat/index?id=thread-jian']] +} +const glyphs: Record = { like: 'heart', comment: 'message', system: 'bell', follow: 'user' } + +export default function NotificationDetailPage() { + const raw = Taro.getCurrentInstance().router?.params.type || 'system' + const type = (['like', 'comment', 'system', 'follow'].includes(raw) ? raw : 'system') as Notification['type'] + const summary = seedNotifications.find((item) => item.type === type) || seedNotifications[2] + return 消息分类{summary.title}{summary.subtitle}{summary.unread} 条未读{details[type].map(([source, text, time, route], index) => )}◈ 通知内容为本地演示数据,不会向校外账号发送。 +} diff --git a/miniProgram/src/pages/onboarding/index.config.ts b/miniProgram/src/pages/onboarding/index.config.ts new file mode 100644 index 0000000..4e65a39 --- /dev/null +++ b/miniProgram/src/pages/onboarding/index.config.ts @@ -0,0 +1 @@ +export default definePageConfig({ navigationStyle: 'custom' }) diff --git a/miniProgram/src/pages/onboarding/index.h5.tsx b/miniProgram/src/pages/onboarding/index.h5.tsx new file mode 100644 index 0000000..dd0f132 --- /dev/null +++ b/miniProgram/src/pages/onboarding/index.h5.tsx @@ -0,0 +1 @@ +export { default } from '@/h5/GoldenRoute' diff --git a/miniProgram/src/pages/onboarding/index.tsx b/miniProgram/src/pages/onboarding/index.tsx index c6cfe8b..c09e3be 100644 --- a/miniProgram/src/pages/onboarding/index.tsx +++ b/miniProgram/src/pages/onboarding/index.tsx @@ -1,3 +1,22 @@ -import { View } from '@tarojs/components' -import { AppShell } from '../../components/AppShell' -export default function OnboardingPage() { return 新手指引准备中 } +import { useState } from 'react' +import { Button, Image, Text, View } from '@tarojs/components' +import { Brand } from '@/components/ui' +import { Glyph } from '@/components/Glyph' +import { demoRepository } from '@/domain/repository' +import { navigationAdapter } from '@/platform' + +const steps = [ + { mood: 'guide-search' as const, title: '快速找到一本书', text: '使用搜索栏与分类入口,按课程、ISBN 或书名找到需要的教材。', targets: ['搜索栏', '分类筛选', '推荐书籍'] }, + { mood: 'question' as const, title: '看懂商品与状态', text: '价格、成色、校区和卖家信息一目了然,已售商品会清晰标注。', targets: ['商品信息', '收藏与联系', '交易状态'] }, + { mood: 'guide-trade' as const, title: '发布并完成交易', text: '从底栏一键发布,站内联系同学,再约在校内安心见面。', targets: ['发布入口', '消息中心', '个人中心'] } +] +export default function OnboardingPage() { + const [index, setIndex] = useState(0) + const step = steps[index] + const complete = async () => { await demoRepository.completeOnboarding(); await navigationAdapter.switchTab('/pages/home/index') } + const next = async () => { if (index < steps.length - 1) setIndex(index + 1); else await complete() } + return + + 新手指引 {index + 1}/3STEP 0{index + 1}{step.title}{step.text}{step.targets.map((target) => {target})}{steps.map((_, dot) => )}{index > 0 && } + +} diff --git a/miniProgram/src/pages/profile/index.config.ts b/miniProgram/src/pages/profile/index.config.ts new file mode 100644 index 0000000..9411eb8 --- /dev/null +++ b/miniProgram/src/pages/profile/index.config.ts @@ -0,0 +1 @@ +export default definePageConfig({ navigationStyle: 'custom', usingComponents: { 'custom-tab-bar': '../../custom-tab-bar/index' } }) diff --git a/miniProgram/src/pages/profile/index.h5.tsx b/miniProgram/src/pages/profile/index.h5.tsx new file mode 100644 index 0000000..dd0f132 --- /dev/null +++ b/miniProgram/src/pages/profile/index.h5.tsx @@ -0,0 +1 @@ +export { default } from '@/h5/GoldenRoute' diff --git a/miniProgram/src/pages/profile/index.tsx b/miniProgram/src/pages/profile/index.tsx index 3d06f1a..4b24ab5 100644 --- a/miniProgram/src/pages/profile/index.tsx +++ b/miniProgram/src/pages/profile/index.tsx @@ -1,3 +1,29 @@ -import { View } from '@tarojs/components' -import { AppShell } from '../../components/AppShell' -export default function ProfilePage() { return 个人中心准备中 } +import { useCallback, useState } from 'react' +import { Button, Image, Text, View } from '@tarojs/components' +import { useDidShow } from '@tarojs/taro' +import { AppShell, Avatar } from '@/components/ui' +import { Glyph } from '@/components/Glyph' +import { demoRepository } from '@/domain/repository' +import type { User } from '@/domain/types' +import { feedbackAdapter, navigationAdapter } from '@/platform' + +export default function ProfilePage() { + const [user, setUser] = useState() + const [counts, setCounts] = useState([0, 0, 0]) + const load = useCallback(() => Promise.all([demoRepository.getProfile(), demoRepository.listFavorites(), demoRepository.listMyListings(), demoRepository.listThreads()]).then(([profile, favorites, listings, threads]) => { setUser(profile); setCounts([favorites.length, listings.length, threads.length]) }), []) + useDidShow(() => { void load() }) + const reset = async () => { if (await feedbackAdapter.confirm('重置演示数据', '将清理 Taro 新版中的收藏、草稿、消息和图片,不影响旧 H5。')) { await demoRepository.resetDemoData(); await feedbackAdapter.toast('演示数据已重置'); await load() } } + if (!user) return 托比正在准备个人主页… + + return + {user.name} LV.12 · 书海漫游者 学生认证{user.campus}校区 · 北京理工大学{user.bio} + + Tobby 提醒:让闲置继续流动,也会遇见更多书友。 + 书籍管理 navigationAdapter.go('/pages/my-listings/index')} /> navigationAdapter.go('/pages/favorites/index')} /> + 体验与帮助 navigationAdapter.go('/pages/onboarding/index')} /> navigationAdapter.go('/pages/states/index?type=index')} /> + +} + +function MenuButton({ glyph, label, detail, onClick, danger = false, id }: { glyph: 'book' | 'heart' | 'refresh' | 'sparkle'; label: string; detail: string; onClick: () => void; danger?: boolean; id?: string }) { + return +} diff --git a/miniProgram/src/pages/publish/index.config.ts b/miniProgram/src/pages/publish/index.config.ts new file mode 100644 index 0000000..9411eb8 --- /dev/null +++ b/miniProgram/src/pages/publish/index.config.ts @@ -0,0 +1 @@ +export default definePageConfig({ navigationStyle: 'custom', usingComponents: { 'custom-tab-bar': '../../custom-tab-bar/index' } }) diff --git a/miniProgram/src/pages/publish/index.h5.tsx b/miniProgram/src/pages/publish/index.h5.tsx new file mode 100644 index 0000000..dd0f132 --- /dev/null +++ b/miniProgram/src/pages/publish/index.h5.tsx @@ -0,0 +1 @@ +export { default } from '@/h5/GoldenRoute' diff --git a/miniProgram/src/pages/publish/index.tsx b/miniProgram/src/pages/publish/index.tsx index 0932c8a..46fbd1e 100644 --- a/miniProgram/src/pages/publish/index.tsx +++ b/miniProgram/src/pages/publish/index.tsx @@ -1,3 +1,40 @@ -import { View } from '@tarojs/components' -import { AppShell } from '../../components/AppShell' -export default function PublishPage() { return 发布流程准备中 } +import { useEffect, useState } from 'react' +import { Button, Image, Input, Picker, Text, Textarea, View } from '@tarojs/components' +import { AppShell, BookCover } from '@/components/ui' +import { Glyph } from '@/components/Glyph' +import { listingAssistant } from '@/domain/assistant' +import { demoRepository } from '@/domain/repository' +import type { Campus, Condition, PublishDraft } from '@/domain/types' +import { feedbackAdapter, mediaAdapter, navigationAdapter } from '@/platform' + +const categories = ['教材教辅', '专业课', '考研考公', '文学小说'] +const conditions: Condition[] = ['全新', '九成新', '八成新', '七成新及以下'] +const campuses: Campus[] = ['中关村', '良乡', '西山', '珠海'] +const emptyDraft: PublishDraft = { title: '', author: '', isbn: '', category: '教材教辅', course: '', price: '', originalPrice: '', condition: '九成新', campus: '良乡', description: '', tags: [], mediaIds: [] } + +export default function PublishPage() { + const [step, setStep] = useState(1) + const [draft, setDraft] = useState(emptyDraft) + const [aiLoading, setAiLoading] = useState(false) + const [errors, setErrors] = useState([]) + useEffect(() => { void demoRepository.getDraft().then((saved) => saved && setDraft(saved)) }, []) + const patch = (next: Partial) => setDraft((current) => ({ ...current, ...next })) + const pick = async () => { const selected = await mediaAdapter.pick(); const saved = await mediaAdapter.persist(selected); patch({ mediaIds: [...draft.mediaIds, ...saved.map((item) => item.id)].slice(0, 6) }) } + const generate = async () => { setAiLoading(true); const result = await listingAssistant.generate(draft); patch({ ...result, author: draft.author || '同济大学数学系 编', isbn: draft.isbn || '978-7-5608-9493-7', category: '教材教辅', course: draft.course || '高等数学', price: draft.price || '26', originalPrice: draft.originalPrice || '49.8', condition: '九成新' }); setAiLoading(false); setStep(2) } + const validate = () => { const next = [!draft.title && '请填写书名', !draft.author && '请填写作者', !draft.price && '请填写价格', !draft.description && '请填写商品简介'].filter(Boolean) as string[]; setErrors(next); return next.length === 0 } + const next = () => { if (step === 1) setStep(2); else if (validate()) setStep(3) } + const save = async () => { await demoRepository.saveDraft(draft); await feedbackAdapter.toast('草稿已保存') } + const publish = async () => { if (!validate()) return setStep(2); await demoRepository.publishListing(draft); await navigationAdapter.go('/pages/states/index?type=published') } + + return + {['上传图片', '填写信息', '确认发布'].map((label, index) => = index + 1 ? 'active' : ''}`} key={label}>{index + 1}{label}{index < 2 && })} + {step === 1 && <>{draft.mediaIds.map((id, index) => 图片 {index + 1})}拍下封面,托比来帮你补全信息~✦ Tobby 一键成文上传封面后,自动生成书名、ISBN、分类与简介。} + {step === 2 && patch({ title: event.detail.value })} /> patch({ author: event.detail.value })} /> patch({ isbn: event.detail.value })} /> patch({ category: categories[Number(event.detail.value)] })}>{draft.category} patch({ condition: conditions[Number(event.detail.value)] })}>{draft.condition} patch({ price: event.detail.value })} placeholder='¥ 0.00' /> patch({ campus: campuses[Number(event.detail.value)] })}>{draft.campus}