@oj-module/cli 0.2.2 → 0.2.5
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.
- package/devkit/README.md +14 -3
- package/devkit/SKILL.md +16 -4
- package/devkit/framework-dev.md +8 -6
- package/devkit/manual.md +243 -23
- package/package.json +2 -2
- package/shell-dist/assets/runtime.js +143 -8
- package/shell-dist/index.html +2 -2
- package/shell-dist/versions.json +3 -3
- package/src/args.ts +67 -0
- package/src/build.ts +11 -3
- package/src/bundle.ts +197 -0
- package/src/contract/__tests__/handler-scan.test.ts +82 -0
- package/src/contract/check.ts +2 -1
- package/src/contract/handler-scan.ts +32 -0
- package/src/deterministic-tar.ts +120 -0
- package/src/dev.ts +4 -2
- package/src/enable.ts +28 -0
- package/src/index.ts +63 -2
- package/src/info.ts +3 -2
- package/src/init.ts +147 -14
- package/src/install.ts +268 -0
- package/src/keygen.ts +88 -0
- package/src/layout.ts +31 -0
- package/src/lifecycle/__tests__/authoring.test.ts +109 -0
- package/src/lifecycle/__tests__/bundle.test.ts +150 -0
- package/src/lifecycle/__tests__/deterministic-tar.test.ts +145 -0
- package/src/lifecycle/__tests__/fixtures/README.md +59 -0
- package/src/lifecycle/__tests__/fixtures/fixture-invalid/EXPECTED-VIOLATIONS.md +27 -0
- package/src/lifecycle/__tests__/fixtures/fixture-invalid/api/src/Demo/manifest.yaml +6 -0
- package/src/lifecycle/__tests__/fixtures/fixture-invalid/manifest.yaml +40 -0
- package/src/lifecycle/__tests__/fixtures/fixture-invalid/web/src/Demo/entry.ts +14 -0
- package/src/lifecycle/__tests__/fixtures/fixture-invalid/web/src/Demo/locales/en-US.json +12 -0
- package/src/lifecycle/__tests__/fixtures/fixture-invalid/web/src/Demo/locales/zh-CN.json +12 -0
- package/src/lifecycle/__tests__/fixtures/fixture-valid/api/src/demo-solution/manifest.yaml +9 -0
- package/src/lifecycle/__tests__/fixtures/fixture-valid/api/src/demo-solution/migrations/0001__init.sql +6 -0
- package/src/lifecycle/__tests__/fixtures/fixture-valid/api/src/demo-solution/ping/api.ts +9 -0
- package/src/lifecycle/__tests__/fixtures/fixture-valid/api/src/demo-solution/schema.yaml +9 -0
- package/src/lifecycle/__tests__/fixtures/fixture-valid/manifest.yaml +96 -0
- package/src/lifecycle/__tests__/fixtures/fixture-valid/web/src/demo-solution/entry.ts +23 -0
- package/src/lifecycle/__tests__/fixtures/fixture-valid/web/src/demo-solution/locales/en-US.json +29 -0
- package/src/lifecycle/__tests__/fixtures/fixture-valid/web/src/demo-solution/locales/zh-CN.json +29 -0
- package/src/lifecycle/__tests__/fixtures/sig/demo-solution-0.2.0.tgz +0 -0
- package/src/lifecycle/__tests__/fixtures/sig/demo-solution-0.2.0.tgz.bad.sig +7 -0
- package/src/lifecycle/__tests__/fixtures/sig/demo-solution-0.2.0.tgz.sig +7 -0
- package/src/lifecycle/__tests__/fixtures/sig/demo-solution-0.2.0.tgz.unknown.sig +7 -0
- package/src/lifecycle/__tests__/fixtures/sig/gen-signed-fixtures.d.mts +21 -0
- package/src/lifecycle/__tests__/fixtures/sig/gen-signed-fixtures.mjs +196 -0
- package/src/lifecycle/__tests__/helpers.ts +78 -0
- package/src/lifecycle/__tests__/install.test.ts +514 -0
- package/src/lifecycle/__tests__/keygen.test.ts +61 -0
- package/src/lifecycle/__tests__/manifest-contract.test.ts +228 -0
- package/src/lifecycle/__tests__/publish.test.ts +80 -0
- package/src/lifecycle/__tests__/sig-fixtures.test.ts +100 -0
- package/src/lifecycle/__tests__/sign.test.ts +131 -0
- package/src/lifecycle/__tests__/smoke.test.ts +61 -0
- package/src/lifecycle/__tests__/trust.test.ts +177 -0
- package/src/lifecycle/__tests__/uninstall.test.ts +87 -0
- package/src/lifecycle/keygen.ts +40 -0
- package/src/lifecycle/sign.ts +74 -0
- package/src/manifest-contract.ts +696 -0
- package/src/oj-cert.ts +19 -0
- package/src/oj-cmd.ts +3 -3
- package/src/preview.ts +2 -2
- package/src/publish.ts +150 -0
- package/src/sign.ts +128 -0
- package/src/site.ts +146 -0
- package/src/trust.ts +116 -0
- package/src/uninstall.ts +29 -0
- package/src/usage.ts +35 -1
- package/templates/README.md +1 -1
- package/templates/api/config.yaml +47 -0
- package/templates/api/seed.mysql.sql +1 -1
- package/templates/api/seed.pg.sql +1 -1
- package/templates/api/src/_platform/_lifecycle/atomic.ts +98 -0
- package/templates/api/src/_platform/_lifecycle/history.ts +31 -0
- package/templates/api/src/_platform/_lifecycle/installer.ts +1080 -0
- package/templates/api/src/_platform/_lifecycle/lock.ts +148 -0
- package/templates/api/src/_platform/_lifecycle/semver.ts +61 -0
- package/templates/api/src/_platform/_lifecycle/sha384.ts +187 -0
- package/templates/api/src/_platform/_lifecycle/state.ts +256 -0
- package/templates/api/src/_platform/_lifecycle/steps/deploy-web.ts +182 -0
- package/templates/api/src/_platform/_lifecycle/steps/download.ts +90 -0
- package/templates/api/src/_platform/_lifecycle/steps/extract.ts +239 -0
- package/templates/api/src/_platform/_lifecycle/steps/migrate.ts +363 -0
- package/templates/api/src/_platform/_lifecycle/steps/preflight.ts +590 -0
- package/templates/api/src/_platform/_lifecycle/steps/register.ts +211 -0
- package/templates/api/src/_platform/_lifecycle/steps/reload.ts +81 -0
- package/templates/api/src/_platform/_lifecycle/steps/smoke.ts +216 -0
- package/templates/api/src/_platform/_lifecycle/steps/verify.ts +207 -0
- package/templates/api/src/_platform/_lifecycle/tasks.ts +119 -0
- package/templates/api/src/_platform/_lifecycle/text-edit.ts +110 -0
- package/templates/api/src/_platform/_lifecycle/tgz-guard.ts +41 -0
- package/templates/api/src/_platform/_lifecycle/trust.ts +229 -0
- package/templates/api/src/_platform/_lifecycle/types.ts +94 -0
- package/templates/api/src/_platform/_lifecycle/uninstall.ts +283 -0
- package/templates/api/src/_platform/_lifecycle/verify-checks.ts +228 -0
- package/templates/api/src/_platform/_lifecycle/verify-report.ts +92 -0
- package/templates/api/src/_platform/_shared/service/access.ts +2 -2
- package/templates/api/src/_platform/_shared/service/settings.ts +10 -1
- package/templates/api/src/_platform/_shared/service/solution-perms.ts +14 -7
- package/templates/api/src/_platform/_shared/site-facade.ts +44 -0
- package/templates/api/src/_platform/manifest.yaml +1 -0
- package/templates/api/src/_platform/market/api.ts +883 -0
- package/templates/api/src/_platform/market/bootstrap.ts +39 -0
- package/templates/api/src/_platform/migrations/0010__sys_solution_route.mysql.sql +17 -0
- package/templates/api/src/_platform/migrations/0010__sys_solution_route.pg.sql +16 -0
- package/templates/api/src/_platform/migrations/0010__sys_solution_route.sql +18 -0
- package/templates/api/src/_platform/migrations/0011__sys_setting_group_label.mysql.sql +2 -0
- package/templates/api/src/_platform/migrations/0011__sys_setting_group_label.sql +4 -0
- package/templates/api/src/_platform/migrations/0012__market_history.mysql.sql +13 -0
- package/templates/api/src/_platform/migrations/0012__market_history.pg.sql +12 -0
- package/templates/api/src/_platform/migrations/0012__market_history.sql +14 -0
- package/templates/api/src/_platform/schema.yaml +21 -4
- package/templates/api/src/_platform/seed.sql +2 -2
- package/templates/api/src/_platform/solutions/api.ts +212 -0
- package/templates/api/src/demo/manifest.yaml +5 -0
- package/templates/api/src/demo/migrations/0001__create_todos.sql +9 -0
- package/templates/api/src/demo/schema.yaml +11 -0
- package/templates/api/src/demo/seed.sql +5 -0
- package/templates/api/src/demo/todos/api.ts +59 -0
- package/templates/api/src/home/line/api.ts +57 -0
- package/templates/api/src/home/manifest.yaml +6 -0
- package/templates/api/src/home/migrations/0001__create_home_tables.sql +13 -0
- package/templates/api/src/home/pie/api.ts +40 -0
- package/templates/api/src/home/schema.yaml +14 -0
- package/templates/api/src/home/seed.sql +70 -0
- package/templates/api/src/system/oplog/api.ts +44 -2
- package/templates/api/tests/fixture.ts +16 -0
- package/templates/api/tests/lifecycle/atomic-state.spec.ts +183 -0
- package/templates/api/tests/lifecycle/bootstrap.spec.ts +116 -0
- package/templates/api/tests/lifecycle/deploy-smoke.spec.ts +492 -0
- package/templates/api/tests/lifecycle/installer.spec.ts +1218 -0
- package/templates/api/tests/lifecycle/market-api.spec.ts +971 -0
- package/templates/api/tests/lifecycle/migrate.spec.ts +575 -0
- package/templates/api/tests/lifecycle/preflight.spec.ts +255 -0
- package/templates/api/tests/lifecycle/register.spec.ts +194 -0
- package/templates/api/tests/lifecycle/semver.spec.ts +43 -0
- package/templates/api/tests/lifecycle/sha384.spec.ts +48 -0
- package/templates/api/tests/lifecycle/sig-fixtures.spec.ts +65 -0
- package/templates/api/tests/lifecycle/solutions-api.spec.ts +98 -0
- package/templates/api/tests/lifecycle/steps-fs.spec.ts +623 -0
- package/templates/api/tests/lifecycle/text-edit.spec.ts +177 -0
- package/templates/api/tests/lifecycle/tgz-guard.spec.ts +103 -0
- package/templates/api/tests/lifecycle/trust.spec.ts +310 -0
- package/templates/api/tests/lifecycle/uninstall.spec.ts +386 -0
- package/templates/api/tests/lifecycle/verify-checks.spec.ts +385 -0
- package/templates/api/tests/lifecycle/verify-report.spec.ts +290 -0
- package/templates/api/tests/rbac-settings.spec.ts +8 -0
- package/templates/init.include.yaml +56 -0
- package/templates/openapi.json +527 -0
- package/templates/package.json +52 -0
- package/templates/web/src/_platform/__client/api.schemas.ts +8 -0
- package/templates/web/src/_platform/__client/api.ts +335 -0
- package/templates/web/src/about/entry.ts +42 -0
- package/templates/web/src/about/locales/en-US.json +16 -0
- package/templates/web/src/about/locales/zh-CN.json +16 -0
- package/templates/web/src/about/pages/constants.ts +20 -0
- package/templates/web/src/about/pages/index.tsx +135 -0
- package/templates/web/src/access/entry.ts +74 -0
- package/templates/web/src/access/locales/en-US.json +46 -0
- package/templates/web/src/access/locales/zh-CN.json +46 -0
- package/templates/web/src/access/pages/access-mode/index.tsx +16 -0
- package/templates/web/src/access/pages/admin-visible/index.tsx +16 -0
- package/templates/web/src/access/pages/button-control/index.tsx +181 -0
- package/templates/web/src/access/pages/common-visible/index.tsx +16 -0
- package/templates/web/src/access/pages/page-control/index.tsx +142 -0
- package/templates/web/src/demo/__client/api.schemas.ts +20 -0
- package/templates/web/src/demo/__client/api.ts +89 -0
- package/templates/web/src/exception/entry.ts +80 -0
- package/templates/web/src/exception/locales/en-US.json +13 -0
- package/templates/web/src/exception/locales/zh-CN.json +13 -0
- package/templates/web/src/exception/pages/403/index.tsx +30 -0
- package/templates/web/src/exception/pages/404/index.tsx +30 -0
- package/templates/web/src/exception/pages/500/index.tsx +30 -0
- package/templates/web/src/exception/pages/unknown-component/index.tsx +38 -0
- package/templates/web/src/home/__client/api.schemas.ts +22 -0
- package/templates/web/src/home/__client/api.ts +113 -0
- package/templates/web/src/login/locales/en-US.json +6 -0
- package/templates/web/src/login/locales/zh-CN.json +6 -0
- package/templates/web/src/login/pages/login.tsx +67 -18
- package/templates/web/src/oj-market/__tests__/CardGrid.test.tsx +93 -0
- package/templates/web/src/oj-market/__tests__/HistoryDrawer.test.tsx +28 -0
- package/templates/web/src/oj-market/__tests__/InstallDialog.test.tsx +69 -0
- package/templates/web/src/oj-market/__tests__/RollbackDialog.test.tsx +43 -0
- package/templates/web/src/oj-market/__tests__/UninstallConfirm.test.tsx +30 -0
- package/templates/web/src/oj-market/__tests__/marketClient.fake.ts +70 -0
- package/templates/web/src/oj-market/__tests__/poll.test.ts +24 -0
- package/templates/web/src/oj-market/__tests__/render.tsx +14 -0
- package/templates/web/src/oj-market/__tests__/runtime-stub.ts +14 -0
- package/templates/web/src/oj-market/__tests__/semver.test.ts +26 -0
- package/templates/web/src/oj-market/api/MarketClientProvider.tsx +12 -0
- package/templates/web/src/oj-market/api/client.ts +135 -0
- package/templates/web/src/oj-market/api/context.ts +11 -0
- package/templates/web/src/oj-market/api/defaultClient.ts +7 -0
- package/templates/web/src/oj-market/components/CardGrid.tsx +76 -0
- package/templates/web/src/oj-market/components/CardItem.tsx +102 -0
- package/templates/web/src/oj-market/components/DetailDrawer.tsx +53 -0
- package/templates/web/src/oj-market/components/HistoryDrawer.tsx +75 -0
- package/templates/web/src/oj-market/components/InstallDialog.tsx +112 -0
- package/templates/web/src/oj-market/components/RollbackDialog.tsx +79 -0
- package/templates/web/src/oj-market/components/UninstallConfirm.tsx +74 -0
- package/templates/web/src/oj-market/entry.ts +27 -0
- package/templates/web/src/oj-market/hooks/useMarket.ts +91 -0
- package/templates/web/src/oj-market/locales/en-US.json +100 -0
- package/templates/web/src/oj-market/locales/zh-CN.json +100 -0
- package/templates/web/src/oj-market/pages/MarketApp.tsx +136 -0
- package/templates/web/src/oj-market/types.ts +84 -0
- package/templates/web/src/oj-market/utils/poll.ts +36 -0
- package/templates/web/src/oj-market/utils/semver.ts +14 -0
- package/templates/web/src/outside/entry.ts +80 -0
- package/templates/web/src/outside/locales/en-US.json +10 -0
- package/templates/web/src/outside/locales/zh-CN.json +10 -0
- package/templates/web/src/personal-center/entry.ts +1 -10
- package/templates/web/src/personal-center/locales/en-US.json +1 -5
- package/templates/web/src/personal-center/locales/zh-CN.json +1 -5
- package/templates/web/src/route-nest/entry.ts +73 -0
- package/templates/web/src/route-nest/locales/en-US.json +9 -0
- package/templates/web/src/route-nest/locales/zh-CN.json +9 -0
- package/templates/web/src/route-nest/pages/menu1/menu1-1/index.tsx +5 -0
- package/templates/web/src/route-nest/pages/menu1/menu1-2/index.tsx +5 -0
- package/templates/web/src/route-nest/pages/menu2/index.tsx +5 -0
- package/templates/web/src/system/__client/api.schemas.ts +12 -0
- package/templates/web/src/system/__client/api.ts +25 -1
- package/templates/web/src/system/pages/oplog/index.tsx +1 -1
- package/templates/web/src/system/pages/roles/index.tsx +1 -0
- package/templates/web/src/system/pages/settings/index.tsx +1 -1
- package/templates/web/src/system/pages/users/index.tsx +1 -1
- package/templates/web.config.ts +32 -40
- package/vendor/host-versions.json +3 -3
- package/templates/pnpm-workspace.yaml +0 -14
- package/templates/web/src/personal-center/pages/settings/index.tsx +0 -5
package/src/usage.ts
CHANGED
|
@@ -15,8 +15,11 @@ export function usageText(): string {
|
|
|
15
15
|
开发模式快捷键(仅 TTY 终端,类 Vite):
|
|
16
16
|
r 强制重建并热更新 h 显示帮助 c 清屏 o 浏览器打开
|
|
17
17
|
q 退出(后端 oj 一并终止)
|
|
18
|
-
ojm build
|
|
18
|
+
ojm build [--bundle] [--out <dir>]
|
|
19
19
|
构建后端(oj build)与模块产物(含全站合并)
|
|
20
|
+
--bundle 方案包构建:manifest.yaml 契约校验(C2,fail-fast)→ 确定性 tgz
|
|
21
|
+
→ dist/<name>-<version>.tgz + sha256(市场安装器的上游产物)
|
|
22
|
+
--out <dir> --bundle 输出目录(缺省 dist/)
|
|
20
23
|
ojm preview [port] [--oj-static]
|
|
21
24
|
生产形态预览(migrate → oj serve + 静态兜底)
|
|
22
25
|
ojm api [dir] [--check] [--docs] [--exempt <path>]
|
|
@@ -30,6 +33,37 @@ export function usageText(): string {
|
|
|
30
33
|
下载/重装 oj vendor(经 npm 包 @oj-bin/oj;tag 缺省取最新,形如 v0.1.13)
|
|
31
34
|
ojm merge <out.json> <in1.json> [in2.json ...]
|
|
32
35
|
合并多团队清单(R12)
|
|
36
|
+
ojm install <file.tgz | name[@version]> [--url <u>] [--user <u>] [--pass <p>]
|
|
37
|
+
[--name <n>] [--version <v>] [--locale <zh-CN|en-US>]
|
|
38
|
+
安装方案包到目标站点(P1-13):本地 tgz 走 file 上传(<name>-<version>.tgz 文件名推导
|
|
39
|
+
身份,可 --name/--version 覆盖);name[@version] 走 CDN 市场源。登录 → 提交 → 轮询任务
|
|
40
|
+
至终态并打印结果(失败附原因 + 指引,--locale 切双语)
|
|
41
|
+
ojm enable|disable <name> [--url <u>] [--user <u>] [--pass <p>]
|
|
42
|
+
启用/禁用已装方案(D12 四处同写:锁 / sidecar / sys_solution_route / modules.json)
|
|
43
|
+
ojm uninstall <name> [--url <u>] [--user <u>] [--pass <p>]
|
|
44
|
+
卸载已装方案(P1-15a:四处同删 + 权限级联清理 + 版本目录移除;站点至少保留一个已锁模块)
|
|
45
|
+
ojm trust ls|add|revoke|confirm [--url <u>] [--user <u>] [--pass <p>]
|
|
46
|
+
发布方信任库管理(P2-2/3,站点 .solutions/trusted-keys.yaml):
|
|
47
|
+
ls <key_id 前缀?> 列出已信任 key(含 sha256 指纹分组展示)
|
|
48
|
+
add <key_id> <pub> 新增信任(64 hex 公钥;首次绑定不可改)
|
|
49
|
+
revoke <key_id> 吊销(阻断新装/升级,不动已装方案)
|
|
50
|
+
confirm --task <id> TOFU 确认:把 needs_trust 终态待确认 key 入库
|
|
51
|
+
站点寻址:--url/--user/--pass,或环境变量 OJM_URL / OJM_USER / OJM_PASS
|
|
52
|
+
ojm keygen --id <publisher.id> [--out <dir>] [--yes]
|
|
53
|
+
生成 Ed25519 签名密钥对(P2-1):私钥默认 ~/.ojm/keys/<id>/ 永不出目录(--out 指到
|
|
54
|
+
工程树内须 --yes 显式确认——私钥入仓即泄露);打印公钥 hex 供 ojm trust add / 模板回填
|
|
55
|
+
ojm sign <file.tgz> [--id <publisher.id>] [--key <pem>] [--check]
|
|
56
|
+
detached 侧车签名(P2-4):产出 <tgz>.sig(ojm install 自动探测随包上传);
|
|
57
|
+
私钥缺省取 ~/.ojm/keys/<id>/private.pem(--key 指定 pem 时须同时 --id);
|
|
58
|
+
--check 离线自检签名(不必靠宿主装失败发现签错)
|
|
59
|
+
站点寻址:--url/--user/--pass,或环境变量 OJM_URL / OJM_USER / OJM_PASS
|
|
60
|
+
(缺省 http://127.0.0.1:9778;凭据只走内存不落盘)
|
|
61
|
+
ojm publish <dir> [--id <publisher.id>] [--key <pem>] [--check]
|
|
62
|
+
索引发布(P3-5/6/7):重算 <dir>/bundles.yaml + manifests.yaml(确定性
|
|
63
|
+
stringify,消弭格式漂移)→ 对两份索引各产出 detached 侧车签名 <kind>.yaml.sig
|
|
64
|
+
(与 archive .sig 同构,公钥取 ~/.ojm/keys/<id>/private.pem,缺省 --id 推导)→ 写回
|
|
65
|
+
<dir>。CDN 侧 resolveCdn/index 拉取索引时校验签名(篡改/不符即拒,G4 fail-closed)。
|
|
66
|
+
--check 离线自检两份索引签名
|
|
33
67
|
ojm test|exec|openapi|migrate|schema [args...]
|
|
34
68
|
透传给 oj 同名子命令(自动补 -c <project>/api/config.yaml;其余参数原样转发)
|
|
35
69
|
例:ojm test --anonymous / ojm migrate --db report / ojm openapi --check
|
package/templates/README.md
CHANGED
|
@@ -1,6 +1,26 @@
|
|
|
1
1
|
# oj 服务配置(字段语义见 oj 后端开发手册 oj-api-dev / 或 oj --help)。
|
|
2
2
|
# 本文件由 ojm init 生成;config 内相对路径相对本文件所在目录。
|
|
3
3
|
# 更多能力见手册 §10:vars / broker / tasks / oidc / ws / html_meta / secrets。
|
|
4
|
+
#
|
|
5
|
+
# ---- 证书与密钥的唯一落点:`./config/`(= api/config/,本文件同级的子目录)----
|
|
6
|
+
# 三件套由 `ojm init` 现场签发(dev 缺证时 `ojm dev` 也会补签),逐把的作用与后果:
|
|
7
|
+
#
|
|
8
|
+
# ① private.pem —— 证书签发私钥(RSA 2048)。只用来给 ③ 签名,**oj 不读它**,
|
|
9
|
+
# 也绝不出部署机、不入仓。丢了不需要恢复:重新签发一套即可(旧的 ③ 作废)。
|
|
10
|
+
# ② public.pem —— 与 ① 成对的公钥,oj 启动时拿它验 ③ 的 RS256 签名。
|
|
11
|
+
# 配错路径或与 ③ 不是同一对 → oj 验签失败、启动即拒(读作「证书无效」)。
|
|
12
|
+
# 由 server.public_key_path 引用。
|
|
13
|
+
# ③ cert.jws —— JWS 证书(RS256 紧凑三段,payload 仅 nbf/exp),**oj 的启动闸门**:
|
|
14
|
+
# 缺失、过期、签名对不上 → fail-fast 拒启,devkit 手册明确**无任何 config/CLI 绕过开关**。
|
|
15
|
+
# 默认有效期 3650 天(短有效期等于定时炸弹);过期只能重新签发一套 ①②③。
|
|
16
|
+
# 由 server.certificate_path 引用。
|
|
17
|
+
#
|
|
18
|
+
# 另有一对与上面无关的密钥(jwt_secret 密封用,init 密封成功后追加到本文件末尾):
|
|
19
|
+
# secrets.private_key_path ./config/secrets-private.pem 解 jwt_secret 密文的私钥,只放部署机
|
|
20
|
+
# secrets.public_key_path ./config/secrets-public.pem 加密用的公钥,可随代码分发
|
|
21
|
+
# (密文形如 ENC 后跟方括号包裹的字串;未密封时 config 里是 32 字节十六进制明文)
|
|
22
|
+
#
|
|
23
|
+
# ojm 侧的解析入口是 `resolveCertDir()`,由本文件位置派生;改落点只需动那一处 + 本段注释。
|
|
4
24
|
|
|
5
25
|
# 站点挂载(oj v0.1.58 起顶层扁平表:一行=一个 URL 前缀+一个目录,api/web 恰好其一)。
|
|
6
26
|
# 被删除的 server.api_prefix / app_spa_fallback 已由 mounts 取代;
|
|
@@ -33,6 +53,9 @@ server:
|
|
|
33
53
|
route_timeouts: []
|
|
34
54
|
# ---- 统一响应头(v0.1.30)----
|
|
35
55
|
response_headers: {}
|
|
56
|
+
# ---- 热更端点(ojm install 的 reloading 段消费;显式关闭 = 安装器 reloading 段可读失败)----
|
|
57
|
+
# ojm:reload
|
|
58
|
+
reload_api: true
|
|
36
59
|
# ---- 直传路由 PUT {base}/blob/{key} 的体积上限(v0.1.30,默认 1GiB)----
|
|
37
60
|
# 与 max_upload_bytes(multipart,默认 10MB)是两套闸,别混。
|
|
38
61
|
blob_upload_max_bytes: 1073741824
|
|
@@ -43,6 +66,30 @@ server:
|
|
|
43
66
|
db:
|
|
44
67
|
default: 'sqlite://db.sqlite' # 相对 config 目录;缺文件自动建空库
|
|
45
68
|
|
|
69
|
+
# ---- 安装序号(ojm install 每次安装自增一次,作为 reload 热更触发变更——unchanged 判定基于
|
|
70
|
+
# config 文档 sha,无落盘变更则热更恒失败。勿删行/勿手工回写旧值。)----
|
|
71
|
+
vars:
|
|
72
|
+
ojm_install_seq: 0
|
|
73
|
+
|
|
74
|
+
# ---- 平台 exec 白名单(ojm install 的解压/迁移两处消费;模板逐字对齐 lifecycle steps 命令构造,
|
|
75
|
+
# 不得增删——多一个 token 都会 NotCapable)----
|
|
76
|
+
platform:
|
|
77
|
+
# ---- U6 信任库加固(P3-1;P2-2 红线 spike 结论)----
|
|
78
|
+
# 威胁:devkit 0.1.75 语义下 fs: 段对全部模块生效(jail = fs.root),且 trusted_paths 只增不减——
|
|
79
|
+
# 信任库落在第三方方案模块可写的 fs.root 内即可被其伪造信任锚。加固须两端配合:
|
|
80
|
+
# ① 本模板已将信任库默认路径移出 modules/ 安装子树(见 _lifecycle 默认 `.solutions/trusted-keys.yaml`,
|
|
81
|
+
# 落在 fs.root 之外的部署根,第三方方案模块 jail 之外);
|
|
82
|
+
# ② **部署侧**须按 oj 语义补 `platform.trusted_paths`(指向运行时信任库目录,该目录须先存在——
|
|
83
|
+
# oj 对不存在的 trusted_paths 装配 fail-fast,故不可在模板里硬编码尚未创建的目录)显式授权给
|
|
84
|
+
# _platform 特权模块写信任库,并收窄第三方方案模块的 fs.root 至其安装子树,方可彻底隔离。
|
|
85
|
+
# 本仓负责①(代码路径);②属部署/上游配置,留作部署清单项(P3-1 备案,不硬编码以免 oj serve 装配失败)。
|
|
86
|
+
exec:
|
|
87
|
+
_platform:
|
|
88
|
+
allow:
|
|
89
|
+
- 'tar -tvzf ${path:archive}'
|
|
90
|
+
- 'tar -xzf ${path:archive} -C ${path:dest}'
|
|
91
|
+
- 'oj migrate --format json -d ${path:dir} ${raw:module}'
|
|
92
|
+
|
|
46
93
|
# ---- LDAP 连接段(D1/PRD §4.5 两段式之连接段;oj 插件严格解析本段,未知键启动 fail-fast——只写下列键)----
|
|
47
94
|
# 取消注释并填值即接通目录服务;应用映射段在 DB/设置页(ldap.enabled、ldap_base_dn、
|
|
48
95
|
# ldap_uid_attr、ldap_email_attr,group=ldap,即时生效)。本段改动属 restart_pending,需重启。
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
-- 系统设置默认值(PRD §4.3;注释内禁英文分号)
|
|
2
2
|
INSERT IGNORE INTO sys_setting (key, module, `group`, type, value, default_value, label_key, secret, update_time) VALUES ('framework.site_title', 'framework', 'general', 'string', 'React Antd Admin', 'React Antd Admin', 'system:setting.site_title', 0, 0);
|
|
3
|
-
INSERT IGNORE INTO sys_setting (key, module, `group`, type, value, default_value, label_key, secret, update_time) VALUES ('
|
|
3
|
+
INSERT IGNORE INTO sys_setting (key, module, `group`, type, value, default_value, label_key, secret, update_time) VALUES ('framework.market_cdn_url', 'framework', 'security', 'string', '', '', 'system:setting.market_cdn_url', 0, 0);
|
|
4
4
|
INSERT IGNORE INTO sys_setting (key, module, `group`, type, value, default_value, label_key, secret, update_time) VALUES ('ldap.enabled', 'ldap', 'login', 'bool', '0', '0', 'system:setting.ldap_enabled', 0, 0);
|
|
5
5
|
INSERT IGNORE INTO sys_setting (key, module, `group`, type, value, default_value, label_key, secret, update_time) VALUES ('sso.enabled', 'sso', 'login', 'bool', '0', '0', 'system:setting.sso_enabled', 0, 0);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
-- 系统设置默认值(PRD §4.3;注释内禁英文分号)
|
|
2
2
|
INSERT INTO sys_setting (key, module, "group", type, value, default_value, label_key, secret, update_time) VALUES ('framework.site_title', 'framework', 'general', 'string', 'React Antd Admin', 'React Antd Admin', 'system:setting.site_title', 0, 0) ON CONFLICT DO NOTHING;
|
|
3
|
-
INSERT INTO sys_setting (key, module, "group", type, value, default_value, label_key, secret, update_time) VALUES ('
|
|
3
|
+
INSERT INTO sys_setting (key, module, "group", type, value, default_value, label_key, secret, update_time) VALUES ('framework.market_cdn_url', 'framework', 'security', 'string', '', '', 'system:setting.market_cdn_url', 0, 0) ON CONFLICT DO NOTHING;
|
|
4
4
|
INSERT INTO sys_setting (key, module, "group", type, value, default_value, label_key, secret, update_time) VALUES ('ldap.enabled', 'ldap', 'login', 'bool', '0', '0', 'system:setting.ldap_enabled', 0, 0) ON CONFLICT DO NOTHING;
|
|
5
5
|
INSERT INTO sys_setting (key, module, "group", type, value, default_value, label_key, secret, update_time) VALUES ('sso.enabled', 'sso', 'login', 'bool', '0', '0', 'system:setting.sso_enabled', 0, 0) ON CONFLICT DO NOTHING;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// 状态文件原子写底座(D13):state.yaml / manifests.yaml / modules.json / 任务文件
|
|
2
|
+
// 一切状态落盘统一走这里——同目录 tmp + rename 原子替换,读者永远见不到半截文件
|
|
3
|
+
// (rename 同目录即同文件系统,POSIX 语义下原子替换 inode)。
|
|
4
|
+
// fs 依赖从 globalThis.fs 取(平台 isolate 注入 FsApi 面;测试注入 node:fs/promises 适配),
|
|
5
|
+
// 签名不携带 fs 参数(DIP:依赖结构化最小面 FsFace,两实现天然兼容)。
|
|
6
|
+
// 写失败(writeFile/rename 抛错)时尽力清理 tmp 后原样上抛,目标旧文件不受影响。
|
|
7
|
+
|
|
8
|
+
export interface FsFace {
|
|
9
|
+
writeFile: (path: string, data: Uint8Array) => Promise<void>
|
|
10
|
+
readFile: (path: string) => Promise<Uint8Array>
|
|
11
|
+
mkdir: (path: string, opts?: { recursive?: boolean }) => Promise<void>
|
|
12
|
+
remove: (path: string, opts?: { recursive?: boolean }) => Promise<void>
|
|
13
|
+
rename: (oldPath: string, newPath: string) => Promise<void>
|
|
14
|
+
/** 复制文件(R14 迁移前置备份:sqlite 库 copy 为 <db>.bak-<ts>);两路径须同文件系统无需递归 */
|
|
15
|
+
copyFile: (src: string, dest: string) => Promise<void>
|
|
16
|
+
/** 列目录成员名(不含路径;不含 . / ..) */
|
|
17
|
+
readdir: (path: string) => Promise<string[]>
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 随机 id:oj isolate 的 crypto 增补面(api-manual §crypto)只有 randomHex,无 Web 的 randomUUID
|
|
22
|
+
* ——有 randomUUID 用之(Node 测试侧),否则 randomHex(16) 兜底(真机冒烟 P1-13 实测,附录 B-9 同源缺面)。
|
|
23
|
+
*/
|
|
24
|
+
export function randomId(): string {
|
|
25
|
+
const c = (globalThis as { crypto?: { randomUUID?: () => string, randomHex?: (n?: number) => string } }).crypto;
|
|
26
|
+
if (c?.randomUUID !== undefined)
|
|
27
|
+
return c.randomUUID();
|
|
28
|
+
if (c?.randomHex !== undefined)
|
|
29
|
+
return c.randomHex(16);
|
|
30
|
+
throw new Error("atomic: 随机数面不可用(globalThis.crypto 缺 randomUUID/randomHex)");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 「路径不存在」判别(isolate 双端,B-11 真机实测补面):Node/测试侧 = NotFound 且 .code
|
|
35
|
+
* 为 ENOENT;oj 真机(0.1.78 实测)= TypeError "invalid_argument"(deno ext 对缺失目标的
|
|
36
|
+
* readFile/remove 报错形态,无 .code)。前置:调用方 fs 调用形状合法(路径为字符串)——
|
|
37
|
+
* 此时 invalid_argument 只能来自缺失目标,语义等价 ENOENT。
|
|
38
|
+
*/
|
|
39
|
+
export function isMissingPath(e: unknown): boolean {
|
|
40
|
+
if ((e as { code?: string } | null)?.code === "ENOENT") {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
return e instanceof TypeError && e.message === "invalid_argument";
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function fsFace(): FsFace {
|
|
47
|
+
const f = (globalThis as { fs?: Partial<FsFace> & { readDir?: (path: string) => Promise<AsyncIterable<{ name: string }>> } }).fs;
|
|
48
|
+
if (f === undefined) {
|
|
49
|
+
throw new Error("atomic: 平台 fs 面不可用(globalThis.fs 未注入),无法落盘");
|
|
50
|
+
}
|
|
51
|
+
if (f.copyFile !== undefined && f.readdir !== undefined) {
|
|
52
|
+
return f as FsFace;
|
|
53
|
+
}
|
|
54
|
+
// oj fs 全局面缺 copyFile、目录列举叫 readDir 且形状是 AsyncIterable<DirEntry>(api-manual §fs)
|
|
55
|
+
// ——在此单点适配到生命周期代码消费的 FsFace(P1-13 真机冒烟实测缺面,契约附录 B-9)。
|
|
56
|
+
return {
|
|
57
|
+
writeFile: (path, data) => f.writeFile!(path, data),
|
|
58
|
+
readFile: path => f.readFile!(path),
|
|
59
|
+
mkdir: (path, opts) => f.mkdir!(path, opts),
|
|
60
|
+
remove: (path, opts) => f.remove!(path, opts),
|
|
61
|
+
rename: (oldPath, newPath) => f.rename!(oldPath, newPath),
|
|
62
|
+
// ponytail: copyFile 经字节中转(V8 常驻峰值 = 文件大小);sqlite 备份上 GB 时须上游补原生 copy
|
|
63
|
+
copyFile: f.copyFile ?? (async (src, dest) => f.writeFile!(dest, await f.readFile!(src))),
|
|
64
|
+
readdir: f.readdir ?? (async (path) => {
|
|
65
|
+
const names: string[] = [];
|
|
66
|
+
for await (const e of await f.readDir!(path))
|
|
67
|
+
names.push(e.name);
|
|
68
|
+
return names;
|
|
69
|
+
}),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const encoder = new TextEncoder();
|
|
74
|
+
|
|
75
|
+
export async function atomicWriteText(path: string, content: string): Promise<void> {
|
|
76
|
+
const f = fsFace();
|
|
77
|
+
// tmp 与目标同目录:保证 rename 不跨文件系统;随机后缀防并发写者互踩同一 tmp
|
|
78
|
+
const slash = path.lastIndexOf("/");
|
|
79
|
+
const dir = slash === -1 ? "" : path.slice(0, slash);
|
|
80
|
+
const base = slash === -1 ? path : path.slice(slash + 1);
|
|
81
|
+
const tmp = `${dir === "" ? "" : `${dir}/`}${base}.${randomId()}.tmp`;
|
|
82
|
+
if (dir !== "") {
|
|
83
|
+
await f.mkdir(dir, { recursive: true });
|
|
84
|
+
}
|
|
85
|
+
try {
|
|
86
|
+
await f.writeFile(tmp, encoder.encode(content));
|
|
87
|
+
await f.rename(tmp, path);
|
|
88
|
+
}
|
|
89
|
+
catch (e) {
|
|
90
|
+
try {
|
|
91
|
+
await f.remove(tmp, { recursive: true });
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// 清理失败不掩盖原始错误
|
|
95
|
+
}
|
|
96
|
+
throw e;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// market_history 留痕(P1-15a 缺口 A,P4 上收 _platform):install / enable / disable / uninstall
|
|
2
|
+
// 四类动作共用的平台级留痕出口(前端 HistoryDrawer 消费面)。表由 _platform 自带迁移创建
|
|
3
|
+
// (0012__market_history),归平台核心所有;守卫式 insert 仍兜底表缺失/写失败,静默跳过,
|
|
4
|
+
// 不阻断主流程(历史是观测面,不是业务正确性依赖;与终态审计附录 B-5 同语义)。
|
|
5
|
+
// 参数化 insert,与 audit.ts 同纪律(值不拼字符串)。
|
|
6
|
+
|
|
7
|
+
// db 为 oj isolate 注入全局(同模板 service 层惯例,installer.ts 同款;测试由夹具装 globalThis.db)
|
|
8
|
+
declare const db: { exec: (sql: string, params: unknown[]) => Promise<unknown> };
|
|
9
|
+
|
|
10
|
+
export interface HistoryRow {
|
|
11
|
+
solution: string
|
|
12
|
+
version: string
|
|
13
|
+
action: "install" | "enable" | "disable" | "uninstall"
|
|
14
|
+
status: string
|
|
15
|
+
/** 操作人(用户名;编排层可得则传,缺省 null) */
|
|
16
|
+
operator: string | null
|
|
17
|
+
message: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** 守卫式 insert:表不存在/写失败一律静默(留痕失败不影响主流程) */
|
|
21
|
+
export async function recordHistory(row: HistoryRow): Promise<void> {
|
|
22
|
+
try {
|
|
23
|
+
await db.exec(
|
|
24
|
+
"insert into market_history (solution, version, action, status, operator, message, created_at) values (?, ?, ?, ?, ?, ?, ?)",
|
|
25
|
+
[row.solution, row.version, row.action, row.status, row.operator, row.message, Math.floor(Date.now() / 1000)],
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
// 表不存在(市场方案未装)或写失败:静默跳过,不阻断主流程
|
|
30
|
+
}
|
|
31
|
+
}
|