extore 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- extore-0.4.0/.dockerignore +8 -0
- extore-0.4.0/.env.example +3 -0
- extore-0.4.0/.github/FUNDING.yml +2 -0
- extore-0.4.0/.github/workflows/ci.yml +32 -0
- extore-0.4.0/.gitignore +13 -0
- extore-0.4.0/.gitmodules +3 -0
- extore-0.4.0/.python-version +1 -0
- extore-0.4.0/DESIGN.md +31 -0
- extore-0.4.0/Dockerfile +11 -0
- extore-0.4.0/LICENSE +21 -0
- extore-0.4.0/PKG-INFO +173 -0
- extore-0.4.0/PRODUCT.md +45 -0
- extore-0.4.0/README.md +143 -0
- extore-0.4.0/compose.yaml +32 -0
- extore-0.4.0/deploy/arch/PKGBUILD +34 -0
- extore-0.4.0/deploy/arch/extore-admin +6 -0
- extore-0.4.0/deploy/arch/extore-api.service +24 -0
- extore-0.4.0/deploy/arch/extore-worker.service +25 -0
- extore-0.4.0/deploy/arch/extore.env +2 -0
- extore-0.4.0/deploy/arch/extore.sysusers +1 -0
- extore-0.4.0/deploy/nginx.conf +38 -0
- extore-0.4.0/docs/acceptance.md +128 -0
- extore-0.4.0/docs/getting-started.md +189 -0
- extore-0.4.0/docs/protocol.md +405 -0
- extore-0.4.0/docs/python-sdk.md +186 -0
- extore-0.4.0/docs/webmcp.md +358 -0
- extore-0.4.0/extore/__init__.py +0 -0
- extore-0.4.0/extore/app.py +1051 -0
- extore-0.4.0/extore/auth.py +263 -0
- extore-0.4.0/extore/card_tracking.py +557 -0
- extore-0.4.0/extore/cli.py +157 -0
- extore-0.4.0/extore/config.py +23 -0
- extore-0.4.0/extore/db.py +165 -0
- extore-0.4.0/extore/files.py +496 -0
- extore-0.4.0/extore/link_access.py +360 -0
- extore-0.4.0/extore/models.py +353 -0
- extore-0.4.0/extore/processors.py +79 -0
- extore-0.4.0/extore/sdk/__init__.py +6 -0
- extore-0.4.0/extore/sdk/client.py +80 -0
- extore-0.4.0/extore/sdk/script.py +99 -0
- extore-0.4.0/extore/security.py +267 -0
- extore-0.4.0/extore/service.py +452 -0
- extore-0.4.0/extore/source.py +40 -0
- extore-0.4.0/extore/static/app.js +1156 -0
- extore-0.4.0/extore/static/cards.js +616 -0
- extore-0.4.0/extore/static/customer-motion.js +400 -0
- extore-0.4.0/extore/static/index.html +55 -0
- extore-0.4.0/extore/static/logo.svg +1 -0
- extore-0.4.0/extore/static/perforation.svg +1 -0
- extore-0.4.0/extore/static/preferences.js +161 -0
- extore-0.4.0/extore/static/product-export.js +223 -0
- extore-0.4.0/extore/static/products.js +746 -0
- extore-0.4.0/extore/static/source-link.js +20 -0
- extore-0.4.0/extore/static/style.css +1477 -0
- extore-0.4.0/extore/static/vendor/dompurify.LICENSE +202 -0
- extore-0.4.0/extore/static/vendor/marked.LICENSE +44 -0
- extore-0.4.0/extore/static/vendor/marked.js +82 -0
- extore-0.4.0/extore/static/vendor/purify.js +7 -0
- extore-0.4.0/extore/static/webmcp.js +2385 -0
- extore-0.4.0/extore/variants.py +117 -0
- extore-0.4.0/extore/worker.py +329 -0
- extore-0.4.0/processors/official/.github/workflows/ci.yml +22 -0
- extore-0.4.0/processors/official/.gitignore +9 -0
- extore-0.4.0/processors/official/LICENSE +22 -0
- extore-0.4.0/processors/official/README.md +118 -0
- extore-0.4.0/processors/official/extore_processors/__init__.py +25 -0
- extore-0.4.0/processors/official/extore_processors/__main__.py +57 -0
- extore-0.4.0/processors/official/extore_processors/catalog.py +259 -0
- extore-0.4.0/processors/official/pyproject.toml +23 -0
- extore-0.4.0/processors/official/tests/test_processors.py +321 -0
- extore-0.4.0/pyproject.toml +76 -0
- extore-0.4.0/scripts/source_archive.py +56 -0
- extore-0.4.0/scripts/welcome.py +15 -0
- extore-0.4.0/tests/cards.test.cjs +752 -0
- extore-0.4.0/tests/conftest.py +80 -0
- extore-0.4.0/tests/customer-motion.test.cjs +404 -0
- extore-0.4.0/tests/management-copy.test.cjs +470 -0
- extore-0.4.0/tests/preferences.test.cjs +279 -0
- extore-0.4.0/tests/product-export.test.cjs +458 -0
- extore-0.4.0/tests/products-ui.test.cjs +636 -0
- extore-0.4.0/tests/receipt-context.test.cjs +462 -0
- extore-0.4.0/tests/test_auth_staff.py +172 -0
- extore-0.4.0/tests/test_card_tracking.py +639 -0
- extore-0.4.0/tests/test_card_variants.py +467 -0
- extore-0.4.0/tests/test_cli.py +245 -0
- extore-0.4.0/tests/test_files.py +439 -0
- extore-0.4.0/tests/test_link_access.py +456 -0
- extore-0.4.0/tests/test_link_migration.py +139 -0
- extore-0.4.0/tests/test_official_processing.py +174 -0
- extore-0.4.0/tests/test_passkeys.py +314 -0
- extore-0.4.0/tests/test_product_links.py +1256 -0
- extore-0.4.0/tests/test_product_queues.py +351 -0
- extore-0.4.0/tests/test_product_variants.py +811 -0
- extore-0.4.0/tests/test_progress_steps.py +438 -0
- extore-0.4.0/tests/test_quick_products.py +541 -0
- extore-0.4.0/tests/test_redemption.py +223 -0
- extore-0.4.0/tests/test_source.py +38 -0
- extore-0.4.0/tests/test_structured_outputs.py +615 -0
- extore-0.4.0/tests/test_webhook_worker.py +177 -0
- extore-0.4.0/tests/webmcp.test.cjs +2400 -0
- extore-0.4.0/uv.lock +1031 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
on: [push, pull_request]
|
|
3
|
+
permissions:
|
|
4
|
+
contents: read
|
|
5
|
+
jobs:
|
|
6
|
+
test:
|
|
7
|
+
runs-on: ubuntu-latest
|
|
8
|
+
steps:
|
|
9
|
+
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
|
10
|
+
with:
|
|
11
|
+
submodules: recursive
|
|
12
|
+
- uses: astral-sh/setup-uv@94527f2e458b27549849d47d273a16bec83a01e9 # v7
|
|
13
|
+
with:
|
|
14
|
+
version: "0.12.20"
|
|
15
|
+
- run: uv sync --frozen --python 3.12
|
|
16
|
+
- run: uv run ruff check extore scripts tests
|
|
17
|
+
- run: uv run ruff format --check extore scripts tests
|
|
18
|
+
- run: uv run pytest -q
|
|
19
|
+
- run: uv run python -m compileall -q extore scripts
|
|
20
|
+
- run: node --check extore/static/app.js
|
|
21
|
+
- run: node --check extore/static/preferences.js
|
|
22
|
+
- run: node --check extore/static/products.js
|
|
23
|
+
- run: node --check extore/static/cards.js
|
|
24
|
+
- run: node --check extore/static/webmcp.js
|
|
25
|
+
- run: node --check extore/static/product-export.js
|
|
26
|
+
- run: node --check extore/static/customer-motion.js
|
|
27
|
+
- run: node --check extore/static/source-link.js
|
|
28
|
+
- run: node --test tests/*.test.cjs
|
|
29
|
+
- run: uv run pytest -q processors/official/tests
|
|
30
|
+
- run: uv build
|
|
31
|
+
- run: uv run extore --help
|
|
32
|
+
- run: uv run extore --version
|
extore-0.4.0/.gitignore
ADDED
extore-0.4.0/.gitmodules
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
extore-0.4.0/DESIGN.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Extore 设计
|
|
2
|
+
|
|
3
|
+
## 使用场景
|
|
4
|
+
顾客在拿到卡密后,快速完成兑换。商家与管理者在桌面或手机上处理任务。页面以完成操作为主。
|
|
5
|
+
|
|
6
|
+
## 视觉语言
|
|
7
|
+
浅色采用温白纸面、深绿色文字与主按钮;暗色采用中性灰黑背景 `#141414`、卡片 `#212121`,保留绿色操作与状态强调。Logo 是入口与交付格组成的几何 E,标题为「Extore · 兑所」。界面参考撕开的纸:面板底边以简化折线形成撕裂边缘,分隔线为 `-- -- --` 分段虚线。无营销插图和虚构商品。
|
|
8
|
+
|
|
9
|
+
首页由两张纸卡构成。左卡标题为「公开商品」,商品 Logo、名称和详情入口直接排列在这张纸内;没有公开商品时显示「暂无公开商品」。商品较多时,列表在纸卡内上下滚动,可视高度按窗口限制,保留标题、分段虚线与撕纸底边。右卡是卡密兑换表单。纸卡以柔和的偏移阴影和轻微透视表现层次;直接点击纸面或聚焦卡内控件时,该纸放大,另一张明显缩小,以 440ms 自然减速过渡交接焦点,不另设切换按钮。输入、按钮、链接与列表滚动保持原生交互,不抢输入焦点。两张纸卡可通过 Tab 聚焦,在纸卡本身使用左右方向键切换;商品列表也可单独聚焦后上下滚动。手机默认显示兑换纸卡,采用原生横向滑动与滚动吸附,纵向浏览商品与横向换纸同时可用。减少动态时直接呈现选择状态。
|
|
10
|
+
|
|
11
|
+
## 显示偏好
|
|
12
|
+
页头提供主题 `auto / light / dark` 和语言 `auto / zh-CN / en` 选择,默认均为 `auto`。自动主题实时响应系统明暗变化;自动语言按 `navigator.languages` 的顺序选择首个支持的中文或英文,无匹配时回退中文。手动选择保存在本浏览器。浅色与深色均保留撕纸折线和分段虚线的视觉语言。
|
|
13
|
+
|
|
14
|
+
## 字体与布局
|
|
15
|
+
中文优先 Noto Sans CJK SC / PingFang SC / Microsoft YaHei;正文 15px,标题 34–48px。卡密与任务 ID 使用等宽字体。主内容最大 1160px,兑换后页面最大 640px。760px 以下一般内容单列,首页双纸卡保留横向滑动;卡密表在手机上按卡密排列,其他后台表格可横向滚动。
|
|
16
|
+
|
|
17
|
+
## 状态与交互
|
|
18
|
+
验证、填写、领取三个步骤。卡密验证成功时,旧兑换纸卡沿折线分成上下两半,以 350ms 的位移和透明度过渡进入填写页;过期或被取消的过渡不继续渲染旧流程。减少动态、页面隐藏或动画 API 不可用时直接呈现下一步。
|
|
19
|
+
|
|
20
|
+
等待页显示实际队列位置、前方任务数、处理说明、已完成与当前步骤,以及处理者上报的百分比。队列由人或 AI 按相同权限规则处理。上下分段虚线分别向右、向左移动,几何纸条作传送装饰;装饰不生成处理进度。用户可暂停动画,减少动态设置、页面隐藏和等待内容离屏时自动停止循环。同一任务的轮询只更新说明、位置、步骤与进度,不反复重建动画。前台轮询间隔为 2.5 秒,隐藏页面降为 15 秒。配置联系邮箱后,「催一下」提供带任务号的 `mailto` 链接,由顾客在自己的邮件应用里确认发送,网站不自动发出催办邮件。
|
|
21
|
+
|
|
22
|
+
管理后台先选择商品,再查看该商品的任务;批量操作始终限定当前商品。商品管理链接只显示授权商品及权限允许的管理标签;店长通过严格缩权的下级链接继续委派。管理链接默认允许一次新登录,次数耗尽不会结束已登录会话;会话可以单独注销,登录、链接使用、委派和注销有访问审计。完成时按任务保存的输出结构填写结果,顾客逐字段领取;服务商品只显示状态。一次领取和销毁需明确确认。控件有焦点样式,错误由 role=alert 输出。左上角 2.5 秒内连续点击 5 次进入后台;这个入口不承担安全认证。
|
|
23
|
+
|
|
24
|
+
队列商品可编辑输入和输出字段,新任务采用新定义;已创建的任务保存自己的输入输出与处理步骤快照,重试和交付继续按该任务定义执行。输出结构不同的任务分别处理。自动商品先选择官方预设,输入输出由代码定义,界面只显示它声明的配置项;发行卡密后仍锁定自动商品的字段结构、处理方式、交付与查看规则、处理器及签名密钥。
|
|
25
|
+
|
|
26
|
+
输入和输出可定义 `file` 字段,分别接收顾客材料和处理者的交付附件,每个文件最多 20 MiB。附件按卡密、任务、字段与权限校验,作为下载文件提供;文件上传不执行程序,也不用于安装处理器代码。界面不提供任意脚本名、代码上传或处理器仓库地址入口。
|
|
27
|
+
|
|
28
|
+
卡密页按商品、规格与批次显示库存和处理统计,支持状态、规格、批次、内部 ID 与尾号筛选。剩余只统计未兑换且未到期的卡密,可重试卡密另列,销售状态由支付平台负责。制卡必须选择启用的规格,卡密绑定规格,顾客兑换时不能改选。规格汇总计入商品总量,旧卡密归默认规格。原文仅在发行返回时展示,可复制整批、选择单条或下载;更改制卡输入会清除当前原文。详情用不含参数、交付内容或原卡密的时间线追踪领取过程。
|
|
29
|
+
|
|
30
|
+
## 内容
|
|
31
|
+
Markdown 用本地 Marked + DOMPurify 渲染,不允许脚本、嵌入、表单或图片。参数名称与教程按语言取值并有默认回退。后台维护界面使用中文。
|
extore-0.4.0/Dockerfile
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
FROM python:3.12-slim
|
|
2
|
+
RUN pip install --no-cache-dir uv==0.12.20 && useradd --uid 10001 --create-home extore
|
|
3
|
+
WORKDIR /app
|
|
4
|
+
COPY pyproject.toml uv.lock ./
|
|
5
|
+
COPY extore ./extore
|
|
6
|
+
COPY scripts ./scripts
|
|
7
|
+
RUN uv sync --frozen --no-dev && chown -R extore:extore /app
|
|
8
|
+
ENV PATH="/app/.venv/bin:$PATH" EXTORE_DATA=/data EXTORE_SCRIPTS=/app/scripts PYTHONUNBUFFERED=1
|
|
9
|
+
USER extore
|
|
10
|
+
EXPOSE 8000
|
|
11
|
+
CMD ["uvicorn", "extore.app:app", "--host", "0.0.0.0", "--port", "8000", "--proxy-headers", "--forwarded-allow-ips=127.0.0.1"]
|
extore-0.4.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Extore contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
extore-0.4.0/PKG-INFO
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: extore
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: Single-merchant redemption and fulfillment with product queues, Passkeys, and native WebMCP
|
|
5
|
+
Project-URL: Homepage, https://extore.lmm.best
|
|
6
|
+
Project-URL: Repository, https://github.com/TokenNotIncluded/extore
|
|
7
|
+
Project-URL: Documentation, https://github.com/TokenNotIncluded/extore/tree/main/docs
|
|
8
|
+
Project-URL: Issues, https://github.com/TokenNotIncluded/extore/issues
|
|
9
|
+
Project-URL: Funding, https://donate.lmm.best/?project=extore
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: fulfillment,passkeys,redemption,sqlite,webmcp
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Environment :: Web Environment
|
|
15
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
20
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
|
21
|
+
Requires-Python: >=3.12
|
|
22
|
+
Requires-Dist: argon2-cffi>=25.1.0
|
|
23
|
+
Requires-Dist: cryptography>=50.0.2
|
|
24
|
+
Requires-Dist: fastapi>=0.142.2
|
|
25
|
+
Requires-Dist: httpx>=0.28.1
|
|
26
|
+
Requires-Dist: python-multipart>=0.0.22
|
|
27
|
+
Requires-Dist: uvicorn[standard]>=0.54.0
|
|
28
|
+
Requires-Dist: webauthn>=3.0.1
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
<p align="center">
|
|
32
|
+
<a href="https://extore.lmm.best">
|
|
33
|
+
<img src="https://raw.githubusercontent.com/TokenNotIncluded/extore/main/extore/static/logo.svg" width="88" height="88" alt="Extore Logo">
|
|
34
|
+
</a>
|
|
35
|
+
</p>
|
|
36
|
+
|
|
37
|
+
<h1 align="center">兑所 · Extore</h1>
|
|
38
|
+
|
|
39
|
+
<p align="center">
|
|
40
|
+
一个商家的卡密兑换与交付网站。<br>
|
|
41
|
+
输入卡密,填写信息,领取商品或查看服务结果。
|
|
42
|
+
</p>
|
|
43
|
+
|
|
44
|
+
<p align="center">
|
|
45
|
+
<a href="https://github.com/TokenNotIncluded/extore/actions/workflows/ci.yml"><img src="https://github.com/TokenNotIncluded/extore/actions/workflows/ci.yml/badge.svg?branch=main" alt="CI"></a>
|
|
46
|
+
<a href="https://pypi.org/project/extore/"><img src="https://img.shields.io/pypi/v/extore?color=245449" alt="PyPI version"></a>
|
|
47
|
+
<a href="https://github.com/TokenNotIncluded/extore/blob/main/pyproject.toml"><img src="https://img.shields.io/badge/Python-3.12%2B-3776AB?logo=python&logoColor=white" alt="Python 3.12+"></a>
|
|
48
|
+
<a href="https://github.com/TokenNotIncluded/extore/blob/main/docs/webmcp.md"><img src="https://img.shields.io/badge/WebMCP-native-245449" alt="Native WebMCP"></a>
|
|
49
|
+
<a href="https://github.com/TokenNotIncluded/extore/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue" alt="MIT License"></a>
|
|
50
|
+
</p>
|
|
51
|
+
|
|
52
|
+
<p align="center">
|
|
53
|
+
<a href="https://extore.lmm.best">在线站点</a> ·
|
|
54
|
+
<a href="https://github.com/TokenNotIncluded/extore/blob/main/docs/getting-started.md">使用文档</a> ·
|
|
55
|
+
<a href="https://github.com/TokenNotIncluded/extore/issues">问题反馈</a> ·
|
|
56
|
+
<a href="https://donate.lmm.best/?project=extore">赞助项目</a>
|
|
57
|
+
</p>
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
Extore 接手支付之后的兑换与交付:验证卡密,将顾客带到对应商品,收集必要信息,再交给商品队列、官方处理器或外部服务。支付与支付订单管理留在上游平台,两边通过制卡接口、Webhook 和签名回调通信。
|
|
62
|
+
|
|
63
|
+
## 能做什么
|
|
64
|
+
|
|
65
|
+
| 能力 | 说明 |
|
|
66
|
+
| --- | --- |
|
|
67
|
+
| 商品与规格 | 多商品、SKU 档位、价格与属性;卡密绑定商品和规格。支持私有商品、快速模板、中英文参数名称与 Markdown 教程。 |
|
|
68
|
+
| 卡密管理 | 使用密码学安全随机数生成卡密,批量发行、复制与下载;按商品、规格、批次和状态跟踪库存与生命周期。原卡密只在发行时显示。 |
|
|
69
|
+
| 独立商品队列 | 每个商品独立领取、筛选和批处理任务,显示真实步骤、处理消息与商品内排位。人或获授权的 AI 使用同一套接口。 |
|
|
70
|
+
| 灵活交付 | 链接、文本、账户信息或文件,也可只返回服务状态。支持一次领取、重复查看、明确失败后的重试,以及顾客主动销毁内容。 |
|
|
71
|
+
| 权限与认证 | 商家后台支持多个 Passkey。商品管理链接默认可登录 1 次,按权限授权、向下委派,并记录会话与操作审计。 |
|
|
72
|
+
| 自动化与二次开发 | 官方开源预设处理器、Python SDK、签名事件与回调;原生定义 **47 个 WebMCP 工具**,按页面、身份与权限动态提供。 |
|
|
73
|
+
| 界面与存储 | SQLite 持久化任务、事件和投递重试;撕纸与分段虚线界面,灰黑暗色主题、中英文语言,默认跟随系统与浏览器。 |
|
|
74
|
+
|
|
75
|
+
顾客上传的是兑换材料,管理者上传的是交付文件。官方处理器来自审核后固定版本的[开源子模块](https://github.com/TokenNotIncluded/extore-processors),商家在预设中选择并填写配置。浏览器 AI 需要原生 WebMCP 支持及实际授权,具体兼容性见[工具文档](https://github.com/TokenNotIncluded/extore/blob/main/docs/webmcp.md#浏览器兼容性)。
|
|
76
|
+
|
|
77
|
+
## 兑换流程
|
|
78
|
+
|
|
79
|
+
```text
|
|
80
|
+
卡密 → 对应商品与规格 → 填写参数 / 上传材料 → 处理任务 → 领取内容 / 查看结果
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
1. 商家创建商品,配置输入、输出、处理方式和查看规则,按规格发行卡密。
|
|
84
|
+
2. 顾客输入有效卡密。非公开商品在验证成功后才显示。
|
|
85
|
+
3. 提交参数后创建唯一任务,重复提交返回同一个任务。
|
|
86
|
+
4. 队列管理者、官方处理器或外部平台完成任务,顾客通过领取链接查看进度和结果。
|
|
87
|
+
|
|
88
|
+
队列商品可修改未来任务的输入输出,已有任务保留各自的结构快照。自动商品发行卡密后锁定处理器和输入输出结构。SKU 价格用于商品定义,上游平台负责实际定价、收款和销售库存。
|
|
89
|
+
|
|
90
|
+
## 快速运行
|
|
91
|
+
|
|
92
|
+
从 [PyPI](https://pypi.org/project/extore/) 安装后,可直接使用 `extore` 命令:
|
|
93
|
+
|
|
94
|
+
```sh
|
|
95
|
+
uv tool install extore
|
|
96
|
+
export EXTORE_DATA="$HOME/.local/share/extore"
|
|
97
|
+
extore init
|
|
98
|
+
extore serve
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
另开一个终端,设置相同的 `EXTORE_DATA` 后运行 `extore worker`。`extore --help` 查看全部命令,`extore --version` 查看版本。生产环境还须配置 `EXTORE_ORIGIN` 并提供 HTTPS,见运行指南。
|
|
102
|
+
|
|
103
|
+
也可以从源码运行:
|
|
104
|
+
|
|
105
|
+
需要 **Python 3.12+、[uv](https://docs.astral.sh/uv/) 和 Linux**。完整环境、部署和备份说明见[运行指南](https://github.com/TokenNotIncluded/extore/blob/main/docs/getting-started.md)。
|
|
106
|
+
|
|
107
|
+
```sh
|
|
108
|
+
git clone --recurse-submodules https://github.com/TokenNotIncluded/extore.git
|
|
109
|
+
cd extore
|
|
110
|
+
uv sync --frozen
|
|
111
|
+
uv run extore init
|
|
112
|
+
uv run extore serve
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
另开一个终端,在项目目录启动 worker,处理自动发货和 Webhook 投递:
|
|
116
|
+
|
|
117
|
+
```sh
|
|
118
|
+
uv run extore worker
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
打开 <http://localhost:8000>。在 2.5 秒内点击左上角 Logo 5 次,或直接访问 `/admin`。首次使用初始化密码注册 Passkey,注册成功后密码登录立即禁用;后续可添加多个 Passkey。
|
|
122
|
+
|
|
123
|
+
<details>
|
|
124
|
+
<summary>首次登录、认证恢复与运行边界</summary>
|
|
125
|
+
|
|
126
|
+
- Passkey 需要 HTTPS 或 localhost;部署前确定固定域名。首次密码会话只能注册 Passkey,不能管理商品。
|
|
127
|
+
- 丢失全部 Passkey 时,须在服务器终端执行 `uv run python -m extore.cli reset-auth`。它撤销全部 Passkey 和登录会话,保留商品、卡密与任务;商品管理链接须另行撤销。详见[认证恢复](https://github.com/TokenNotIncluded/extore/blob/main/docs/getting-started.md#认证恢复)。
|
|
128
|
+
- API 与 worker 共享数据目录和配置,一个数据库只运行一个 worker。数据目录、数据库和 `issuance.key` 都要妥善保护和备份。详见[生产运行](https://github.com/TokenNotIncluded/extore/blob/main/docs/getting-started.md#生产运行)。
|
|
129
|
+
- 领取链接是凭证。一次领取会消耗查看机会;销毁不能撤回已下载的副本、外部内容或历史备份。未知、超时或崩溃的交付默认等待核实,下游须用稳定任务 ID 去重。详见[自动处理与领取](https://github.com/TokenNotIncluded/extore/blob/main/docs/getting-started.md#自动处理与领取)。
|
|
130
|
+
|
|
131
|
+
</details>
|
|
132
|
+
|
|
133
|
+
## 文档
|
|
134
|
+
|
|
135
|
+
| 文档 | 内容 |
|
|
136
|
+
| --- | --- |
|
|
137
|
+
| [快速入门与运行指南](https://github.com/TokenNotIncluded/extore/blob/main/docs/getting-started.md) | 本地运行、管理权限、认证恢复、生产配置、Docker 与 Arch Linux 部署 |
|
|
138
|
+
| [接口与事件协议](https://github.com/TokenNotIncluded/extore/blob/main/docs/protocol.md) | 商品、SKU、卡密、队列、附件、完整事件定义与签名回调 |
|
|
139
|
+
| [原生 WebMCP](https://github.com/TokenNotIncluded/extore/blob/main/docs/webmcp.md) | 47 个工具、浏览器支持、权限范围与确认要求 |
|
|
140
|
+
| [Python SDK](https://github.com/TokenNotIncluded/extore/blob/main/docs/python-sdk.md) | 官方处理器协议、任务结果、外部验签与回调示例 |
|
|
141
|
+
| [验收记录](https://github.com/TokenNotIncluded/extore/blob/main/docs/acceptance.md) | 已记录的验证结果、对接边界与限制 |
|
|
142
|
+
| [产品定义](https://github.com/TokenNotIncluded/extore/blob/main/PRODUCT.md) · [设计说明](https://github.com/TokenNotIncluded/extore/blob/main/DESIGN.md) | 项目范围、交互和视觉原则 |
|
|
143
|
+
|
|
144
|
+
服务运行后,`/docs` 提供交互式 OpenAPI 文档。事件与回调协议版本为 **v1**。
|
|
145
|
+
|
|
146
|
+
## 贡献
|
|
147
|
+
|
|
148
|
+
欢迎通过 [Issues](https://github.com/TokenNotIncluded/extore/issues) 提交可复现的问题或功能建议,也欢迎提交 Pull Request。修改前请阅读[产品定义](https://github.com/TokenNotIncluded/extore/blob/main/PRODUCT.md)与[设计说明](https://github.com/TokenNotIncluded/extore/blob/main/DESIGN.md),保持单商家范围、商品权限隔离和既有视觉语言。
|
|
149
|
+
|
|
150
|
+
常用检查如下;完整检查项以 [CI 工作流](https://github.com/TokenNotIncluded/extore/blob/main/.github/workflows/ci.yml)为准:
|
|
151
|
+
|
|
152
|
+
```sh
|
|
153
|
+
uv run ruff check extore scripts tests
|
|
154
|
+
uv run ruff format --check extore scripts tests
|
|
155
|
+
uv run pytest -q
|
|
156
|
+
node --test tests/*.test.cjs
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Pull Request 请说明行为变化和验证结果。官方预设处理器在[独立仓库](https://github.com/TokenNotIncluded/extore-processors)维护,主项目通过子模块固定版本。反馈或示例中请删除卡密、管理链接、领取凭证、密钥和顾客资料。
|
|
160
|
+
|
|
161
|
+
## 赞助
|
|
162
|
+
|
|
163
|
+
如果 Extore 帮到了你,可以通过 [donate.lmm.best](https://donate.lmm.best/?project=extore) 支持项目维护。
|
|
164
|
+
|
|
165
|
+
<p align="center">
|
|
166
|
+
<a href="https://donate.lmm.best/?project=extore">
|
|
167
|
+
<img src="https://donate.lmm.best/badge.svg?project=extore&currency=CNY&lang=zh-CN&period=all&layout=compact&theme=dark&width=440&title=Extore" width="440" alt="Extore 项目累计赞助">
|
|
168
|
+
</a>
|
|
169
|
+
</p>
|
|
170
|
+
|
|
171
|
+
## 许可证
|
|
172
|
+
|
|
173
|
+
Extore 使用 [MIT License](https://github.com/TokenNotIncluded/extore/blob/main/LICENSE)。官方处理器子模块的许可见[其仓库](https://github.com/TokenNotIncluded/extore-processors/blob/main/LICENSE)。
|
extore-0.4.0/PRODUCT.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Extore · 兑所
|
|
2
|
+
<!-- impeccable:product-schema 1 -->
|
|
3
|
+
|
|
4
|
+
## Platform
|
|
5
|
+
web
|
|
6
|
+
|
|
7
|
+
## Stack
|
|
8
|
+
Python FastAPI、SQLite、原生 HTML/CSS/JavaScript。根据脚本 SDK 需求选择,部署目标为用户指定的 archczy,域名 extore.lmm.best。
|
|
9
|
+
|
|
10
|
+
## Users
|
|
11
|
+
单个商家、通过商品管理链接获得指定权限的店长与处理人员,以及持有卡密的顾客。顾客无需注册。
|
|
12
|
+
|
|
13
|
+
## Product Purpose
|
|
14
|
+
顾客输入卡密、填写商品参数,完成一次兑换,领取交付内容或查看服务状态。支付、外部订单和支付平台交付职责归另一网站。
|
|
15
|
+
|
|
16
|
+
## Operating Context
|
|
17
|
+
队列按商品分开,人和 AI 通过同一套权限接口处理任务;AI 可使用原生 WebMCP。自动处理使用固定版本的官方白名单处理器,或独立外部服务的签名 webhook / 回调。管理者通过限一个商品、可撤销、有期限及登录次数限制的管理链接工作。
|
|
18
|
+
|
|
19
|
+
## Capabilities and Constraints
|
|
20
|
+
SQLite。安全随机且唯一的卡密、一次兑换、可选重复查看或一次查看、可核实后重试。商品可公开或仅持卡可见;队列商品自定义输入参数与多个交付输出字段,支持多语言名称、URL 与 Markdown 教程。服务商品仅显示状态。任务创建时保存输入输出与处理步骤快照;队列商品可调整新任务的字段,已有任务及其重试按原快照处理。自动商品发行卡密后仍冻结字段结构与处理器,以及处理方式、交付和查看规则;字段名称与说明可改善。商家用 Passkey 登录,支持多个 Passkey;首次密码引导注册,SSH 命令恢复。
|
|
21
|
+
|
|
22
|
+
商品支持多个规格,每个规格有稳定 ID、名称、说明、可选参考价格、币种、属性与启用状态。发行卡密时选定规格并保存快照,顾客持卡兑换对应规格,无需自行选规格;已发行规格可以停用,不能删除。卡密支持批次、到期时间、尾号定位、商品和规格统计及不含秘密的时间线。剩余只统计未兑换且未到期的卡密,与原顾客可重试卡密分别计数;销售状态归支付平台。卡密原文只在本次发行返回,可整批或单条复制与下载,历史查询不恢复原文。
|
|
23
|
+
|
|
24
|
+
`file` 输入接收顾客材料,`file` 输出交付处理者上传的附件,每个文件最多 20 MiB。上传与下载限定卡密、任务、字段和对应权限,附件作为下载文件提供;文件不在站点执行,也不是处理器代码上传入口。交付附件同样遵循查看规则和销毁操作,已下载到顾客设备的副本不能撤回。
|
|
25
|
+
|
|
26
|
+
等待页显示实际任务步骤、处理说明、百分比和商品队列排位。纸条与反向滚动虚线仅作装饰,可由用户暂停,并遵循减少动态设置、页面隐藏及离屏暂停。同一任务轮询更新状态,保持已有动画。商品可配置联系邮箱,「催一下」用预填任务信息的 `mailto` 链接打开用户邮件应用,由用户自行发送,网站不自动发邮件。
|
|
27
|
+
|
|
28
|
+
主题和语言默认自动,可分别选择浅色/深色与中文/英文。自动主题实时跟随系统;自动语言按浏览器偏好顺序选择中文或英文,无匹配时回退中文。手动偏好保存在本浏览器。
|
|
29
|
+
|
|
30
|
+
商品管理链接可分别授权队列查看、处理、放行重试、展示与顾客参数编辑、自动发货配置、卡密管理、事件管理与向下委派。自动发货配置须同时获得商品编辑权限,可读写签名密钥、官方处理器配置和重试规则,具有控制该商品外部发货的能力;仅负责商品展示编辑的管理者不获此权限。店长可完全管理指定商品;子链接的权限必须比父链接少,期限不超过父链接,父链接失效则后代也失效。链接不能访问全店设置或管理商家 Passkey。
|
|
31
|
+
|
|
32
|
+
管理链接 `max_uses` 默认 1,限制成功建立新登录的次数,次数耗尽不注销已有会话。子链接次数上限不能超过父链接设定上限。商家管理全店会话;商品管理者可管理自己的会话,拥有向下委派权限时还可管理授权商品的下级会话。登录、链接使用、委派、退出和注销保留审计记录;会话列表显示设备、地址、登录与活动时间,不显示授权凭证。
|
|
33
|
+
|
|
34
|
+
自动处理器来自公开仓库 TokenNotIncluded/extore-processors,在 processors/official 子模块固定到审核过的提交。仅支持官方预设及其代码定义的输入输出;商家不能安装任意程序、上传代码或配置 Git 地址。固定代码按 worker 权限运行,不提供恶意代码沙箱。
|
|
35
|
+
销毁立即撤除应用内交付内容和相关参数;无法撤回他人已下载的内容。
|
|
36
|
+
|
|
37
|
+
## Brand Commitments
|
|
38
|
+
品牌名称为 Extore · 兑所,采用几何 E Logo 与撕纸折线、分段虚线。浅色温白,暗色中性灰黑。首页两张有柔和阴影和轻透视的纸卡,左纸内展示公开商品,右纸输入卡密;桌面点击放大焦点纸卡,手机原生左右滑动且默认兑换卡。卡密验证成功以短暂撕纸过渡进入填写页,减少动态或动画不可用时直接切换。
|
|
39
|
+
|
|
40
|
+
## Product Principles
|
|
41
|
+
- 兑换一次,重试不等于重新发货。
|
|
42
|
+
- 成功必须有可信处理结果,未知状态等待核实。
|
|
43
|
+
- 非公开商品只向持有效卡密的顾客展示。
|
|
44
|
+
- 顾客专注领取,管理者按商品和权限工作,商家管理全店。
|
|
45
|
+
- 店长可以委派更小的权限,不能越过自己的商品、权限或期限。
|
extore-0.4.0/README.md
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://extore.lmm.best">
|
|
3
|
+
<img src="https://raw.githubusercontent.com/TokenNotIncluded/extore/main/extore/static/logo.svg" width="88" height="88" alt="Extore Logo">
|
|
4
|
+
</a>
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
<h1 align="center">兑所 · Extore</h1>
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
一个商家的卡密兑换与交付网站。<br>
|
|
11
|
+
输入卡密,填写信息,领取商品或查看服务结果。
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
<p align="center">
|
|
15
|
+
<a href="https://github.com/TokenNotIncluded/extore/actions/workflows/ci.yml"><img src="https://github.com/TokenNotIncluded/extore/actions/workflows/ci.yml/badge.svg?branch=main" alt="CI"></a>
|
|
16
|
+
<a href="https://pypi.org/project/extore/"><img src="https://img.shields.io/pypi/v/extore?color=245449" alt="PyPI version"></a>
|
|
17
|
+
<a href="https://github.com/TokenNotIncluded/extore/blob/main/pyproject.toml"><img src="https://img.shields.io/badge/Python-3.12%2B-3776AB?logo=python&logoColor=white" alt="Python 3.12+"></a>
|
|
18
|
+
<a href="https://github.com/TokenNotIncluded/extore/blob/main/docs/webmcp.md"><img src="https://img.shields.io/badge/WebMCP-native-245449" alt="Native WebMCP"></a>
|
|
19
|
+
<a href="https://github.com/TokenNotIncluded/extore/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue" alt="MIT License"></a>
|
|
20
|
+
</p>
|
|
21
|
+
|
|
22
|
+
<p align="center">
|
|
23
|
+
<a href="https://extore.lmm.best">在线站点</a> ·
|
|
24
|
+
<a href="https://github.com/TokenNotIncluded/extore/blob/main/docs/getting-started.md">使用文档</a> ·
|
|
25
|
+
<a href="https://github.com/TokenNotIncluded/extore/issues">问题反馈</a> ·
|
|
26
|
+
<a href="https://donate.lmm.best/?project=extore">赞助项目</a>
|
|
27
|
+
</p>
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
Extore 接手支付之后的兑换与交付:验证卡密,将顾客带到对应商品,收集必要信息,再交给商品队列、官方处理器或外部服务。支付与支付订单管理留在上游平台,两边通过制卡接口、Webhook 和签名回调通信。
|
|
32
|
+
|
|
33
|
+
## 能做什么
|
|
34
|
+
|
|
35
|
+
| 能力 | 说明 |
|
|
36
|
+
| --- | --- |
|
|
37
|
+
| 商品与规格 | 多商品、SKU 档位、价格与属性;卡密绑定商品和规格。支持私有商品、快速模板、中英文参数名称与 Markdown 教程。 |
|
|
38
|
+
| 卡密管理 | 使用密码学安全随机数生成卡密,批量发行、复制与下载;按商品、规格、批次和状态跟踪库存与生命周期。原卡密只在发行时显示。 |
|
|
39
|
+
| 独立商品队列 | 每个商品独立领取、筛选和批处理任务,显示真实步骤、处理消息与商品内排位。人或获授权的 AI 使用同一套接口。 |
|
|
40
|
+
| 灵活交付 | 链接、文本、账户信息或文件,也可只返回服务状态。支持一次领取、重复查看、明确失败后的重试,以及顾客主动销毁内容。 |
|
|
41
|
+
| 权限与认证 | 商家后台支持多个 Passkey。商品管理链接默认可登录 1 次,按权限授权、向下委派,并记录会话与操作审计。 |
|
|
42
|
+
| 自动化与二次开发 | 官方开源预设处理器、Python SDK、签名事件与回调;原生定义 **47 个 WebMCP 工具**,按页面、身份与权限动态提供。 |
|
|
43
|
+
| 界面与存储 | SQLite 持久化任务、事件和投递重试;撕纸与分段虚线界面,灰黑暗色主题、中英文语言,默认跟随系统与浏览器。 |
|
|
44
|
+
|
|
45
|
+
顾客上传的是兑换材料,管理者上传的是交付文件。官方处理器来自审核后固定版本的[开源子模块](https://github.com/TokenNotIncluded/extore-processors),商家在预设中选择并填写配置。浏览器 AI 需要原生 WebMCP 支持及实际授权,具体兼容性见[工具文档](https://github.com/TokenNotIncluded/extore/blob/main/docs/webmcp.md#浏览器兼容性)。
|
|
46
|
+
|
|
47
|
+
## 兑换流程
|
|
48
|
+
|
|
49
|
+
```text
|
|
50
|
+
卡密 → 对应商品与规格 → 填写参数 / 上传材料 → 处理任务 → 领取内容 / 查看结果
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
1. 商家创建商品,配置输入、输出、处理方式和查看规则,按规格发行卡密。
|
|
54
|
+
2. 顾客输入有效卡密。非公开商品在验证成功后才显示。
|
|
55
|
+
3. 提交参数后创建唯一任务,重复提交返回同一个任务。
|
|
56
|
+
4. 队列管理者、官方处理器或外部平台完成任务,顾客通过领取链接查看进度和结果。
|
|
57
|
+
|
|
58
|
+
队列商品可修改未来任务的输入输出,已有任务保留各自的结构快照。自动商品发行卡密后锁定处理器和输入输出结构。SKU 价格用于商品定义,上游平台负责实际定价、收款和销售库存。
|
|
59
|
+
|
|
60
|
+
## 快速运行
|
|
61
|
+
|
|
62
|
+
从 [PyPI](https://pypi.org/project/extore/) 安装后,可直接使用 `extore` 命令:
|
|
63
|
+
|
|
64
|
+
```sh
|
|
65
|
+
uv tool install extore
|
|
66
|
+
export EXTORE_DATA="$HOME/.local/share/extore"
|
|
67
|
+
extore init
|
|
68
|
+
extore serve
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
另开一个终端,设置相同的 `EXTORE_DATA` 后运行 `extore worker`。`extore --help` 查看全部命令,`extore --version` 查看版本。生产环境还须配置 `EXTORE_ORIGIN` 并提供 HTTPS,见运行指南。
|
|
72
|
+
|
|
73
|
+
也可以从源码运行:
|
|
74
|
+
|
|
75
|
+
需要 **Python 3.12+、[uv](https://docs.astral.sh/uv/) 和 Linux**。完整环境、部署和备份说明见[运行指南](https://github.com/TokenNotIncluded/extore/blob/main/docs/getting-started.md)。
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
git clone --recurse-submodules https://github.com/TokenNotIncluded/extore.git
|
|
79
|
+
cd extore
|
|
80
|
+
uv sync --frozen
|
|
81
|
+
uv run extore init
|
|
82
|
+
uv run extore serve
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
另开一个终端,在项目目录启动 worker,处理自动发货和 Webhook 投递:
|
|
86
|
+
|
|
87
|
+
```sh
|
|
88
|
+
uv run extore worker
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
打开 <http://localhost:8000>。在 2.5 秒内点击左上角 Logo 5 次,或直接访问 `/admin`。首次使用初始化密码注册 Passkey,注册成功后密码登录立即禁用;后续可添加多个 Passkey。
|
|
92
|
+
|
|
93
|
+
<details>
|
|
94
|
+
<summary>首次登录、认证恢复与运行边界</summary>
|
|
95
|
+
|
|
96
|
+
- Passkey 需要 HTTPS 或 localhost;部署前确定固定域名。首次密码会话只能注册 Passkey,不能管理商品。
|
|
97
|
+
- 丢失全部 Passkey 时,须在服务器终端执行 `uv run python -m extore.cli reset-auth`。它撤销全部 Passkey 和登录会话,保留商品、卡密与任务;商品管理链接须另行撤销。详见[认证恢复](https://github.com/TokenNotIncluded/extore/blob/main/docs/getting-started.md#认证恢复)。
|
|
98
|
+
- API 与 worker 共享数据目录和配置,一个数据库只运行一个 worker。数据目录、数据库和 `issuance.key` 都要妥善保护和备份。详见[生产运行](https://github.com/TokenNotIncluded/extore/blob/main/docs/getting-started.md#生产运行)。
|
|
99
|
+
- 领取链接是凭证。一次领取会消耗查看机会;销毁不能撤回已下载的副本、外部内容或历史备份。未知、超时或崩溃的交付默认等待核实,下游须用稳定任务 ID 去重。详见[自动处理与领取](https://github.com/TokenNotIncluded/extore/blob/main/docs/getting-started.md#自动处理与领取)。
|
|
100
|
+
|
|
101
|
+
</details>
|
|
102
|
+
|
|
103
|
+
## 文档
|
|
104
|
+
|
|
105
|
+
| 文档 | 内容 |
|
|
106
|
+
| --- | --- |
|
|
107
|
+
| [快速入门与运行指南](https://github.com/TokenNotIncluded/extore/blob/main/docs/getting-started.md) | 本地运行、管理权限、认证恢复、生产配置、Docker 与 Arch Linux 部署 |
|
|
108
|
+
| [接口与事件协议](https://github.com/TokenNotIncluded/extore/blob/main/docs/protocol.md) | 商品、SKU、卡密、队列、附件、完整事件定义与签名回调 |
|
|
109
|
+
| [原生 WebMCP](https://github.com/TokenNotIncluded/extore/blob/main/docs/webmcp.md) | 47 个工具、浏览器支持、权限范围与确认要求 |
|
|
110
|
+
| [Python SDK](https://github.com/TokenNotIncluded/extore/blob/main/docs/python-sdk.md) | 官方处理器协议、任务结果、外部验签与回调示例 |
|
|
111
|
+
| [验收记录](https://github.com/TokenNotIncluded/extore/blob/main/docs/acceptance.md) | 已记录的验证结果、对接边界与限制 |
|
|
112
|
+
| [产品定义](https://github.com/TokenNotIncluded/extore/blob/main/PRODUCT.md) · [设计说明](https://github.com/TokenNotIncluded/extore/blob/main/DESIGN.md) | 项目范围、交互和视觉原则 |
|
|
113
|
+
|
|
114
|
+
服务运行后,`/docs` 提供交互式 OpenAPI 文档。事件与回调协议版本为 **v1**。
|
|
115
|
+
|
|
116
|
+
## 贡献
|
|
117
|
+
|
|
118
|
+
欢迎通过 [Issues](https://github.com/TokenNotIncluded/extore/issues) 提交可复现的问题或功能建议,也欢迎提交 Pull Request。修改前请阅读[产品定义](https://github.com/TokenNotIncluded/extore/blob/main/PRODUCT.md)与[设计说明](https://github.com/TokenNotIncluded/extore/blob/main/DESIGN.md),保持单商家范围、商品权限隔离和既有视觉语言。
|
|
119
|
+
|
|
120
|
+
常用检查如下;完整检查项以 [CI 工作流](https://github.com/TokenNotIncluded/extore/blob/main/.github/workflows/ci.yml)为准:
|
|
121
|
+
|
|
122
|
+
```sh
|
|
123
|
+
uv run ruff check extore scripts tests
|
|
124
|
+
uv run ruff format --check extore scripts tests
|
|
125
|
+
uv run pytest -q
|
|
126
|
+
node --test tests/*.test.cjs
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Pull Request 请说明行为变化和验证结果。官方预设处理器在[独立仓库](https://github.com/TokenNotIncluded/extore-processors)维护,主项目通过子模块固定版本。反馈或示例中请删除卡密、管理链接、领取凭证、密钥和顾客资料。
|
|
130
|
+
|
|
131
|
+
## 赞助
|
|
132
|
+
|
|
133
|
+
如果 Extore 帮到了你,可以通过 [donate.lmm.best](https://donate.lmm.best/?project=extore) 支持项目维护。
|
|
134
|
+
|
|
135
|
+
<p align="center">
|
|
136
|
+
<a href="https://donate.lmm.best/?project=extore">
|
|
137
|
+
<img src="https://donate.lmm.best/badge.svg?project=extore&currency=CNY&lang=zh-CN&period=all&layout=compact&theme=dark&width=440&title=Extore" width="440" alt="Extore 项目累计赞助">
|
|
138
|
+
</a>
|
|
139
|
+
</p>
|
|
140
|
+
|
|
141
|
+
## 许可证
|
|
142
|
+
|
|
143
|
+
Extore 使用 [MIT License](https://github.com/TokenNotIncluded/extore/blob/main/LICENSE)。官方处理器子模块的许可见[其仓库](https://github.com/TokenNotIncluded/extore-processors/blob/main/LICENSE)。
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
services:
|
|
2
|
+
api:
|
|
3
|
+
build: .
|
|
4
|
+
restart: unless-stopped
|
|
5
|
+
ports:
|
|
6
|
+
- "127.0.0.1:8000:8000"
|
|
7
|
+
environment: &env
|
|
8
|
+
EXTORE_ORIGIN: ${EXTORE_ORIGIN:-http://localhost:8000}
|
|
9
|
+
EXTORE_DATA: /data
|
|
10
|
+
EXTORE_SCRIPTS: /app/scripts
|
|
11
|
+
volumes: &volumes
|
|
12
|
+
- ./data:/data
|
|
13
|
+
- ./scripts:/app/scripts:ro
|
|
14
|
+
healthcheck:
|
|
15
|
+
test:
|
|
16
|
+
[
|
|
17
|
+
"CMD",
|
|
18
|
+
"python",
|
|
19
|
+
"-c",
|
|
20
|
+
"import urllib.request; urllib.request.urlopen('http://localhost:8000/health', timeout=5)",
|
|
21
|
+
]
|
|
22
|
+
interval: 30s
|
|
23
|
+
timeout: 5s
|
|
24
|
+
retries: 3
|
|
25
|
+
stop_grace_period: 30s
|
|
26
|
+
worker:
|
|
27
|
+
build: .
|
|
28
|
+
restart: unless-stopped
|
|
29
|
+
command: ["python", "-m", "extore.worker"]
|
|
30
|
+
environment: *env
|
|
31
|
+
volumes: *volumes
|
|
32
|
+
stop_grace_period: 150s
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
pkgname=extore
|
|
2
|
+
pkgver=0.4.0
|
|
3
|
+
pkgrel=3
|
|
4
|
+
pkgdesc='Single-merchant redemption and fulfillment service'
|
|
5
|
+
arch=('x86_64')
|
|
6
|
+
url='https://github.com/TokenNotIncluded/extore'
|
|
7
|
+
license=('MIT')
|
|
8
|
+
depends=('python')
|
|
9
|
+
makedepends=('uv')
|
|
10
|
+
options=('!strip' '!debug')
|
|
11
|
+
backup=('etc/extore/extore.env')
|
|
12
|
+
source=('extore-source.tar.gz')
|
|
13
|
+
sha256sums=('SKIP')
|
|
14
|
+
|
|
15
|
+
build() {
|
|
16
|
+
cd "$srcdir/extore-source"
|
|
17
|
+
uv sync --frozen --no-dev --no-editable --python /usr/bin/python --no-managed-python
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
package() {
|
|
21
|
+
cd "$srcdir/extore-source"
|
|
22
|
+
install -d "$pkgdir/usr/lib/extore"
|
|
23
|
+
cp -a .venv "$pkgdir/usr/lib/extore/"
|
|
24
|
+
# Services and scripts launch via python -m; omit source-bound entrypoints.
|
|
25
|
+
find "$pkgdir/usr/lib/extore/.venv/bin" -type f -delete
|
|
26
|
+
rm -f "$pkgdir"/usr/lib/extore/.venv/lib/python*/site-packages/extore-*.dist-info/direct_url.json
|
|
27
|
+
install -Dm644 deploy/arch/extore-api.service "$pkgdir/usr/lib/systemd/system/extore-api.service"
|
|
28
|
+
install -Dm644 deploy/arch/extore-worker.service "$pkgdir/usr/lib/systemd/system/extore-worker.service"
|
|
29
|
+
install -Dm644 deploy/arch/extore.sysusers "$pkgdir/usr/lib/sysusers.d/extore.conf"
|
|
30
|
+
install -Dm644 deploy/arch/extore.env "$pkgdir/etc/extore/extore.env"
|
|
31
|
+
install -Dm755 deploy/arch/extore-admin "$pkgdir/usr/bin/extore-admin"
|
|
32
|
+
install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
|
|
33
|
+
install -Dm644 processors/official/LICENSE "$pkgdir/usr/share/licenses/$pkgname/official-processors-LICENSE"
|
|
34
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
[Unit]
|
|
2
|
+
Description=Extore redemption API
|
|
3
|
+
After=network.target
|
|
4
|
+
|
|
5
|
+
[Service]
|
|
6
|
+
User=extore
|
|
7
|
+
Group=extore
|
|
8
|
+
EnvironmentFile=/etc/extore/extore.env
|
|
9
|
+
WorkingDirectory=/var/lib/extore
|
|
10
|
+
ExecStart=/usr/lib/extore/.venv/bin/python -m uvicorn extore.app:app --host 127.0.0.1 --port 8095 --forwarded-allow-ips=127.0.0.1
|
|
11
|
+
Restart=on-failure
|
|
12
|
+
RestartSec=5
|
|
13
|
+
StateDirectory=extore
|
|
14
|
+
StateDirectoryMode=0700
|
|
15
|
+
UMask=0077
|
|
16
|
+
NoNewPrivileges=true
|
|
17
|
+
PrivateTmp=true
|
|
18
|
+
ProtectSystem=strict
|
|
19
|
+
ProtectHome=true
|
|
20
|
+
ReadWritePaths=/var/lib/extore
|
|
21
|
+
TimeoutStopSec=30
|
|
22
|
+
|
|
23
|
+
[Install]
|
|
24
|
+
WantedBy=multi-user.target
|