Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,10 @@ output
.playwright-cli
.pytest_cache
__pycache__
.ruff_cache
dist
build
*.egg-info
.coverage
.coverage.*
htmlcov
32 changes: 8 additions & 24 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,34 +25,18 @@ jobs:
sudo meson install -C "$RUNNER_TEMP/extore-bubblewrap-build"
/usr/bin/bwrap --version
- run: uv sync --frozen --python 3.12
- run: uv run ruff check extore scripts tests
- run: uv run ruff format --check extore scripts tests
- run: uv run ruff check extore scripts tests examples
- run: uv run ruff format --check extore scripts tests examples
- run: uv run ruff check --config pyproject.toml processors/official/extore_processors processors/official/tests
- run: uv run ruff format --check --config pyproject.toml processors/official/extore_processors processors/official/tests
- run: uv run pytest -q
- run: uv run python -m compileall -q extore scripts
- run: uv run python -m compileall -q extore scripts examples
- run: uv run python examples/workflows/validate_examples.py
- run: node --check extore/static/account.js
- run: node --check extore/static/vendor/qrcodegen.js
- run: node --check extore/static/totp-qr.js
- run: node --check extore/static/device-login.js
- run: node --check extore/static/pipeline-authorizations.js
- run: |
for file in extore/static/{task-flow,task-flow-editor,text-cards,batch-redemption,proxy-routing,proxy-config}.js; do node --check "$file"; done
- run: node --check extore/static/app.js
- run: node --check extore/static/progress-board.js
- run: node --check extore/static/worker-identity.js
- run: node --check extore/static/preferences.js
- run: node --check extore/static/products.js
- run: node --check extore/static/processor-contribution.js
- run: node --check extore/static/commerce-connect.js
- run: node --check extore/static/cards.js
- run: node --check extore/static/webmcp.js
- run: node --check extore/static/product-export.js
- run: node --check extore/static/customer-motion.js
- run: node --check extore/static/source-link.js
- run: node --check extore/static/cli-prompts.js
- run: node --check extore/static/owner-cli.js
- name: Check all shipped JavaScript
run: |
while IFS= read -r -d '' file; do
node --check "$file"
done < <(find extore/static -type f -name '*.js' -print0)
- run: node --test tests/*.test.cjs
- run: uv run pytest -q processors/official/tests
- run: uv build -q
Expand Down
7 changes: 5 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ __pycache__/
output/
.playwright-cli/
.impeccable/config.local.json

dist/

build/
*.egg-info/
.coverage
.coverage.*
htmlcov/
.ruff_cache/
38 changes: 16 additions & 22 deletions PRODUCT.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,41 +5,35 @@
web

## Stack
Python FastAPI、SQLite、原生 HTML/CSS/JavaScript。根据脚本 SDK 需求选择,部署目标为用户指定的 archczy,域名 extore.lmm.best。
Python FastAPI、SQLite、原生 HTML/CSS/JavaScript。Linux 上运行 API 和 worker;部署地址由配置决定,不绑定开发者的服务器。

## Users
单个商家、通过商品管理链接获得指定权限的店长与处理人员,以及持有卡密的顾客。顾客无需注册。
平台管理员、各店店主、获得商品权限的管理者与人类或 AI 处理者,以及持卡顾客。一个实例可以服务多个独立店铺。顾客无需注册。

## Product Purpose
顾客输入卡密、填写商品参数,完成一次兑换,领取交付内容或查看服务状态。支付、外部订单和支付平台交付职责归另一网站。
顾客用卡密提交需求、查看处理状态、领取交付内容。商家按商品管理卡密和任务。支付、销售订单与实际售价由外部商城负责;Extore 不收款,规格价格只是参考价。

## Operating Context
队列按商品分开,人和 AI 通过同一套权限接口处理任务;AI 可使用原生 WebMCP。自动处理使用固定版本的官方白名单处理器,或独立外部服务的签名 webhook / 回调。管理者通过限一个商品、可撤销、有期限及登录次数限制的管理链接工作。
商品、卡密、任务、附件、配置与授权按店铺隔离。人和 AI 使用相同的权限规则。浏览器、CLI、Python SDK 和原生 WebMCP 是同一业务的入口,不是各自独立的权限体系。

## Capabilities and Constraints
SQLite。安全随机且唯一的卡密、一次兑换、可选重复查看或一次查看、可核实后重试。商品可公开或仅持卡可见;队列商品自定义输入参数与多个交付输出字段,支持多语言名称、URL 与 Markdown 教程。服务商品仅显示状态。任务创建时保存输入输出与处理步骤快照;队列商品可调整新任务的字段,已有任务及其重试按原快照处理。自动商品发行卡密后仍冻结字段结构与处理器,以及处理方式、交付和查看规则;字段名称与说明可改善。商家用 Passkey 登录,支持多个 Passkey;首次密码引导注册,SSH 命令恢复。

商品支持多个规格,每个规格有稳定 ID、名称、说明、可选参考价、币种、属性与启用状态。参考价仅供外部商城配置参考,Extore 只负责兑换与交付,不收款。发行卡密时选定规格并保存快照,顾客持卡兑换对应规格,无需自行选规格;已发行规格可以停用,不能删除。卡密支持批次、到期时间、尾号定位、商品和规格统计及不含秘密的时间线。剩余只统计未兑换且未到期的卡密,与原顾客可重试卡密分别计数;销售状态归支付平台。卡密原文只在本次发行返回,可整批或单条复制与下载,历史查询不恢复原文。
平台管理员使用 Passkey;首次密码只用于平台初始化。店主使用已验证邮箱与密码,可启用 TOTP 或 Passkey。平台恢复命令不重置店主账号。完整规则见[多店与账号](docs/shops.md)。

`file` 输入接收顾客材料,`file` 输出交付处理者上传的附件,每个文件最多 20 MiB。上传与下载限定卡密、任务、字段和对应权限,附件作为下载文件提供;文件不在站点执行,也不是处理器代码上传入口。交付附件同样遵循查看规则和销毁操作,已下载到顾客设备的副本不能撤回。

等待页显示实际任务步骤、处理说明、百分比和商品队列排位。纸条与反向滚动虚线仅作装饰,可由用户暂停,并遵循减少动态设置、页面隐藏及离屏暂停。同一任务轮询更新状态,保持已有动画。商品可配置联系邮箱,「催一下」用预填任务信息的 `mailto` 链接打开用户邮件应用,由用户自行发送,网站不自动发邮件。
## Capabilities and Constraints
卡密绑定发行时的商品、规格和适用配置。已有卡密不继承以后新增的权限或修改额度。普通兑换、文本卡和可选任务流程共存;旧数据通过启动迁移继续使用,不在业务处理中猜测数据库是否缺表。

主题和语言默认自动,可分别选择浅色/深色与中文/英文。自动主题实时跟随系统;自动语言按浏览器偏好顺序选择中文或英文,无匹配时回退中文。手动偏好保存在本浏览器。
任务保存输入、输出与处理步骤快照。支持附件、人工处理、受审核的固定处理器和外部处理服务。处理失败或外部结果不明确时,需要核实,不自动宣称交付成功。修改交付使用卡密冻结的修改额度,不能重新计算为销售库存。

商品管理链接可分别授权队列查看、处理、放行重试、展示与顾客参数编辑、自动发货配置、卡密管理、事件管理与向下委派。自动发货配置须同时获得商品编辑权限,可读写签名密钥、官方处理器配置和重试规则,具有控制该商品外部发货的能力;仅负责商品展示编辑的管理者不获此权限。店长可完全管理指定商品;子链接的权限必须比父链接少,期限不超过父链接,父链接失效则后代也失效。链接不能访问全店设置或管理商家 Passkey。
处理器代码来自固定提交的官方子模块,不接受代码上传、任意仓库、命令或镜像配置。离线处理器需要 bubblewrap 和 libseccomp 隔离,并受资源限制;隔离不可用时拒绝运行,不退回普通进程。隔离不替代源码审核。复杂或联网任务由经过授权的外部执行器处理。见[运行指南](docs/getting-started.md)和[工作流开发](docs/workflow-development.md)。

管理链接 `max_uses` 默认 1,限制成功建立新登录的次数,次数耗尽不注销已有会话。子链接次数上限不能超过父链接设定上限。商家管理全店会话;商品管理者可管理自己的会话,拥有向下委派权限时还可管理授权商品的下级会话。登录、链接使用、委派、退出和注销保留审计记录;会话列表显示设备、地址、登录与活动时间,不显示授权凭证。
管理链接和设备授权有明确的商品范围、权限与有效期。向下委派只能缩小权限。授权撤销影响后续处理;秘密不进入公开提示词或普通查询。见[协议](docs/protocol.md)。

自动处理器来自公开仓库 TokenNotIncluded/extore-processors,在 processors/official 子模块固定到审核过的提交。仅支持官方预设及其代码定义的输入输出;商家不能安装任意程序、上传代码或配置 Git 地址。固定代码按 worker 权限运行,不提供恶意代码沙箱。
销毁立即撤除应用内交付内容和相关参数;无法撤回他人已下载的内容。
卡密原文只在发行时返回。领取和销毁遵循商品规则及各版本的权限。销毁清除应用内对应内容,不能撤回外部副本,也不承诺擦除备份。

## Brand Commitments
品牌名称为 Extore · 兑所,采用几何 E Logo 与撕纸折线、分段虚线。浅色温白,暗色中性灰黑。首页两张有柔和阴影和轻透视的纸卡,左纸内展示公开商品,右纸输入卡密;桌面点击放大焦点纸卡,手机原生左右滑动且默认兑换卡。卡密验证成功以短暂撕纸过渡进入填写页,减少动态或动画不可用时直接切换。
名称为 Extore · 兑所。采用几何 E 标记、撕纸边缘与分段虚线。主题和语言默认跟随系统;动态效果遵循减少动态设置。视觉与交互规范只在 [DESIGN.md](DESIGN.md) 维护,不在此重复尺寸、颜色和动画时长。

## Product Principles
- 兑换一次,重试不等于重新发货。
- 成功必须有可信处理结果,未知状态等待核实。
- 非公开商品只向持有效卡密的顾客展示。
- 顾客专注领取,管理者按商品和权限工作,商家管理全店。
- 店长可以委派更小的权限,不能越过自己的商品、权限或期限。
- 兑换、重试和修改交付各有边界,不把重试当作新销售。
- 成功必须有可信结果;测试通过不等于真实部署、邮件送达或付款成功。
- 每次操作都检查实际店铺、商品和权限,不信任页面隐藏或客户端声明。
- 旧数据升级保留业务记录;数据库结构错误必须暴露,不能静默跳过安全检查。
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ SMTP 凭据、TOTP 密钥与店铺处理器配置加密保存。店主可以回
| [0.10.0 更新说明](https://github.com/TokenNotIncluded/extore/blob/main/docs/releases/0.10.0.md) | 自定义卡密属性、交付后修改权益、历史版本领取与轮次保护 |
| [0.8.2 更新说明](https://github.com/TokenNotIncluded/extore/blob/main/docs/releases/0.8.2.md) | 清空回收站与彻底删除商品;保留已有卡密、任务和交付 |
| [0.8.1 更新说明](https://github.com/TokenNotIncluded/extore/blob/main/docs/releases/0.8.1.md) | 商品删除、回收站恢复与独立删除权限;保留旧卡密和任务 |
| [验收记录](https://github.com/TokenNotIncluded/extore/blob/main/docs/acceptance.md) | 已记录的验证结果、对接边界与限制 |
| [验证指南](https://github.com/TokenNotIncluded/extore/blob/main/docs/acceptance.md) | 当前检查方法、数据升级与真实验收边界 |
| [产品定义](https://github.com/TokenNotIncluded/extore/blob/main/PRODUCT.md) · [设计说明](https://github.com/TokenNotIncluded/extore/blob/main/DESIGN.md) | 项目范围、交互和视觉原则 |

服务运行后,`/docs` 提供交互式 OpenAPI 文档。普通事件和既有回调保持 **v1**;流程私有 Worker 使用独立的 **v2** 签名与节点范围。
Expand Down
Loading
Loading