@oj-module/cli 0.2.66 → 0.2.67

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.
Files changed (187) hide show
  1. package/bin/.oj-version +1 -0
  2. package/bin/oj +4 -0
  3. package/devkit/README.md +15 -7
  4. package/devkit/SKILL.md +30 -1
  5. package/devkit/framework-dev.md +10 -4
  6. package/devkit/manual.md +38 -12
  7. package/devkit/publish-walkthrough.md +110 -37
  8. package/devkit/wecom-internal-app.md +7 -2
  9. package/devkit/wecom-multi-corp-links.md +163 -0
  10. package/package.json +2 -2
  11. package/shell-dist/assets/{index.i0kqbxp050.js → index.6alqyx6ae0.js} +21 -1
  12. package/shell-dist/assets/{runtime.1xfsxcajj0.js → runtime.2dgstpjsu0.js} +3449 -3449
  13. package/shell-dist/index.html +4 -4
  14. package/shell-dist/versions.json +3 -3
  15. package/src/__tests__/publish-keygen.test.ts +157 -0
  16. package/src/__tests__/templates-migration-schema-parity.test.ts +540 -0
  17. package/src/__tests__/templates-schema-columns.test.ts +15 -2
  18. package/src/__tests__/templates-tenant-scope.test.ts +6 -2
  19. package/src/bundle.ts +8 -3
  20. package/src/cli.ts +17 -5
  21. package/src/dev.ts +15 -10
  22. package/src/install.ts +11 -4
  23. package/src/keygen.ts +54 -0
  24. package/src/lifecycle/__tests__/bundle.test.ts +21 -3
  25. package/src/lifecycle/__tests__/fixtures/fixture-valid/api/src/demo-solution/manifest.yaml +1 -1
  26. package/src/lifecycle/__tests__/fixtures/fixture-valid/api/src/demo-solution/migrations/0001__init.sql +2 -2
  27. package/src/lifecycle/__tests__/fixtures/fixture-valid/api/src/demo-solution/schema.yaml +5 -2
  28. package/src/lifecycle/__tests__/fixtures/fixture-valid/manifest.yaml +1 -1
  29. package/src/lifecycle/__tests__/manifest-contract.test.ts +75 -3
  30. package/src/lifecycle/__tests__/smoke.test.ts +2 -2
  31. package/src/manifest-contract.ts +91 -8
  32. package/src/market/bootstrap.ts +26 -2
  33. package/src/market/command.ts +1 -0
  34. package/src/market/publish.ts +5 -1
  35. package/src/market/walkthrough.ts +24 -8
  36. package/src/site.ts +2 -0
  37. package/src/usage.ts +8 -4
  38. package/src/vendor.ts +5 -1
  39. package/templates/config.yaml +4 -2
  40. package/templates/init.include.yaml +8 -3
  41. package/templates/openapi.json +460 -1
  42. package/templates/src/app/api/_platform/_lifecycle/compensate.ts +136 -0
  43. package/templates/src/app/api/_platform/_lifecycle/installer.ts +71 -22
  44. package/templates/src/app/api/_platform/_lifecycle/lock.ts +23 -0
  45. package/templates/src/app/api/_platform/_lifecycle/steps/deploy-web.ts +28 -0
  46. package/templates/src/app/api/_platform/_lifecycle/steps/preflight.ts +46 -0
  47. package/templates/src/app/api/_platform/_lifecycle/steps/reload.ts +100 -36
  48. package/templates/src/app/api/_platform/_lifecycle/steps/smoke.ts +7 -15
  49. package/templates/src/app/api/_platform/_lifecycle/text-edit.ts +71 -19
  50. package/templates/src/app/api/_platform/_lifecycle/types.ts +26 -2
  51. package/templates/src/app/api/_platform/_lifecycle/uninstall.ts +93 -14
  52. package/templates/src/app/api/_platform/_shared/service/domain/settings.ts +8 -4
  53. package/templates/src/app/api/_platform/manifest.yaml +1 -0
  54. package/templates/src/app/api/_platform/market/api.ts +235 -10
  55. package/templates/src/app/api/_platform/migrations/0001__baseline.mysql.sql +178 -0
  56. package/templates/src/app/api/_platform/migrations/0001__baseline.pg.sql +173 -0
  57. package/templates/src/app/api/_platform/migrations/0001__baseline.sql +188 -0
  58. package/templates/src/app/api/_platform/migrations/0002__market_release.mysql.sql +17 -0
  59. package/templates/src/app/api/_platform/migrations/0002__market_release.pg.sql +16 -0
  60. package/templates/src/app/api/_platform/migrations/0002__market_release.sql +33 -0
  61. package/templates/src/app/api/_platform/schema.yaml +18 -0
  62. package/templates/src/app/api/_platform/seed.mysql.sql +10 -0
  63. package/templates/src/app/api/_platform/seed.pg.sql +10 -0
  64. package/templates/src/app/api/auth/_shared/wecom/client.ts +24 -4
  65. package/templates/src/app/api/home/migrations/0001__create_home_tables.mysql.sql +14 -0
  66. package/templates/src/app/api/home/migrations/0001__create_home_tables.pg.sql +14 -0
  67. package/templates/src/app/api/home/migrations/0002__tenant.pg.sql +4 -0
  68. package/templates/src/app/api/home/seed.mysql.sql +71 -0
  69. package/templates/src/app/api/home/seed.pg.sql +71 -0
  70. package/templates/src/app/api/notification/_shared/notify.ts +6 -6
  71. package/templates/src/app/api/notification/migrations/0001__create_notifications.mysql.sql +11 -0
  72. package/templates/src/app/api/notification/migrations/0001__create_notifications.pg.sql +11 -0
  73. package/templates/src/app/api/notification/migrations/0002__notifications_user.mysql.sql +8 -0
  74. package/templates/src/app/api/notification/migrations/0003__notifications_broadcast.mysql.sql +21 -0
  75. package/templates/src/app/api/notification/migrations/0003__notifications_broadcast.pg.sql +22 -0
  76. package/templates/src/app/api/notification/migrations/0004__notifications_broadcast_hidden.mysql.sql +10 -0
  77. package/templates/src/app/api/notification/migrations/0004__notifications_broadcast_hidden.pg.sql +11 -0
  78. package/templates/src/app/api/notification/migrations/0005__tenant.pg.sql +6 -0
  79. package/templates/src/app/api/notification/seed.mysql.sql +8 -0
  80. package/templates/src/app/api/notification/seed.pg.sql +11 -0
  81. package/templates/src/app/api/publish/_shared/identity.ts +69 -0
  82. package/templates/src/app/api/publish/api.ts +349 -0
  83. package/templates/src/app/api/publish/manifest.yaml +8 -0
  84. package/templates/src/app/api/publish/migrations/0001__publish_credential.mysql.sql +23 -0
  85. package/templates/src/app/api/publish/migrations/0001__publish_credential.pg.sql +23 -0
  86. package/templates/src/app/api/publish/migrations/0001__publish_credential.sql +39 -0
  87. package/templates/src/app/api/publish/schema.yaml +33 -0
  88. package/templates/src/app/api/system/login-methods/api.ts +2 -1
  89. package/templates/src/app/web/_platform/__client/api.schemas.ts +15 -0
  90. package/templates/src/app/web/_platform/__client/index.ts +25 -1
  91. package/templates/src/app/web/entry.ts +9 -5
  92. package/templates/src/app/web/home/routes.ts +5 -0
  93. package/templates/src/app/web/login/locales/en-US.json +7 -1
  94. package/templates/src/app/web/login/locales/zh-CN.json +7 -1
  95. package/templates/src/app/web/login/pages/login.tsx +79 -86
  96. package/templates/src/app/web/login/routes.ts +54 -1
  97. package/templates/src/app/web/personal-center/locales/en-US.json +1 -0
  98. package/templates/src/app/web/personal-center/locales/zh-CN.json +1 -0
  99. package/templates/src/app/web/personal-center/pages/my-profile/index.tsx +5 -0
  100. package/templates/src/app/web/system/__client/api.schemas.ts +2 -1
  101. package/templates/src/app/web/system/locales/en-US.json +1 -8
  102. package/templates/src/app/web/system/locales/zh-CN.json +1 -8
  103. package/templates/src/app/web/system/pages/settings/index.tsx +17 -4
  104. package/templates/src/app/web/system/routes.ts +0 -6
  105. package/templates/src/oj-market/web/__tests__/CardGrid.test.tsx +33 -0
  106. package/templates/src/oj-market/web/__tests__/DetailDrawer.test.tsx +69 -0
  107. package/templates/src/oj-market/web/__tests__/marketClient.fake.ts +7 -1
  108. package/templates/src/oj-market/web/api/client.ts +3 -0
  109. package/templates/src/oj-market/web/api/defaultClient.ts +5 -0
  110. package/templates/src/oj-market/web/components/CardItem.tsx +44 -1
  111. package/templates/src/oj-market/web/components/DetailDrawer.tsx +17 -1
  112. package/templates/src/oj-market/web/entry.ts +31 -2
  113. package/templates/src/oj-market/web/locales/en-US.json +5 -1
  114. package/templates/src/oj-market/web/locales/zh-CN.json +5 -1
  115. package/templates/src/oj-market/web/publish/__client/api.schemas.ts +61 -0
  116. package/templates/src/oj-market/web/publish/__client/index.ts +164 -0
  117. package/templates/src/oj-market/web/publish/locales/en-US.json +80 -0
  118. package/templates/src/oj-market/web/publish/locales/zh-CN.json +80 -0
  119. package/templates/src/oj-market/web/publish/pages/history.tsx +112 -0
  120. package/templates/src/oj-market/web/publish/pages/index.tsx +196 -0
  121. package/templates/src/oj-market/web/publish/pages/model.ts +52 -0
  122. package/templates/src/oj-market/web/publish/pages/token-modal.tsx +82 -0
  123. package/templates/src/oj-market/web/publish/routes.ts +41 -0
  124. package/templates/src/oj-market/web/types.ts +30 -0
  125. package/templates/tests/lifecycle/compensate.spec.ts +207 -0
  126. package/templates/tests/lifecycle/deploy-smoke.spec.ts +38 -14
  127. package/templates/tests/lifecycle/installer.spec.ts +28 -9
  128. package/templates/tests/lifecycle/market-api.spec.ts +164 -12
  129. package/templates/tests/lifecycle/preflight.spec.ts +68 -0
  130. package/templates/tests/lifecycle/role-title-translate.spec.ts +2 -32
  131. package/templates/tests/lifecycle/text-edit.spec.ts +45 -27
  132. package/templates/tests/lifecycle/uninstall.spec.ts +36 -0
  133. package/templates/tests/publish-credential.spec.ts +354 -0
  134. package/templates/tests/publish-identity.spec.ts +44 -0
  135. package/templates/tests/wecom-client-timeout.spec.ts +33 -3
  136. package/templates/tests/wecom-landing.spec.ts +63 -1
  137. package/templates/tsconfig.paths.json +1 -0
  138. package/templates/web.config.ts +6 -4
  139. package/vendor/host-versions.json +3 -3
  140. package/templates/seed.mysql.sql +0 -6
  141. package/templates/seed.pg.sql +0 -6
  142. package/templates/src/app/api/_platform/migrations/0001__create_users.mysql.sql +0 -9
  143. package/templates/src/app/api/_platform/migrations/0001__create_users.pg.sql +0 -9
  144. package/templates/src/app/api/_platform/migrations/0001__create_users.sql +0 -7
  145. package/templates/src/app/api/_platform/migrations/0002__add_users_avatar_base64.mysql.sql +0 -3
  146. package/templates/src/app/api/_platform/migrations/0002__add_users_avatar_base64.sql +0 -2
  147. package/templates/src/app/api/_platform/migrations/0003__users_source_display_name.mysql.sql +0 -5
  148. package/templates/src/app/api/_platform/migrations/0003__users_source_display_name.sql +0 -5
  149. package/templates/src/app/api/_platform/migrations/0004__sys_rbac.mysql.sql +0 -70
  150. package/templates/src/app/api/_platform/migrations/0004__sys_rbac.pg.sql +0 -67
  151. package/templates/src/app/api/_platform/migrations/0004__sys_rbac.sql +0 -67
  152. package/templates/src/app/api/_platform/migrations/0005__users_must_change.mysql.sql +0 -3
  153. package/templates/src/app/api/_platform/migrations/0005__users_must_change.sql +0 -2
  154. package/templates/src/app/api/_platform/migrations/0006__users_is_forbidden.mysql.sql +0 -3
  155. package/templates/src/app/api/_platform/migrations/0006__users_is_forbidden.sql +0 -3
  156. package/templates/src/app/api/_platform/migrations/0007__users_email.sql +0 -3
  157. package/templates/src/app/api/_platform/migrations/0008__sys_refresh_token.mysql.sql +0 -10
  158. package/templates/src/app/api/_platform/migrations/0008__sys_refresh_token.pg.sql +0 -10
  159. package/templates/src/app/api/_platform/migrations/0008__sys_refresh_token.sql +0 -11
  160. package/templates/src/app/api/_platform/migrations/0009__sys_throttle.mysql.sql +0 -12
  161. package/templates/src/app/api/_platform/migrations/0009__sys_throttle.pg.sql +0 -12
  162. package/templates/src/app/api/_platform/migrations/0009__sys_throttle.sql +0 -13
  163. package/templates/src/app/api/_platform/migrations/0010__sys_solution_route.mysql.sql +0 -17
  164. package/templates/src/app/api/_platform/migrations/0010__sys_solution_route.pg.sql +0 -16
  165. package/templates/src/app/api/_platform/migrations/0010__sys_solution_route.sql +0 -18
  166. package/templates/src/app/api/_platform/migrations/0011__sys_setting_group_label.mysql.sql +0 -2
  167. package/templates/src/app/api/_platform/migrations/0011__sys_setting_group_label.sql +0 -4
  168. package/templates/src/app/api/_platform/migrations/0012__market_history.mysql.sql +0 -13
  169. package/templates/src/app/api/_platform/migrations/0012__market_history.pg.sql +0 -12
  170. package/templates/src/app/api/_platform/migrations/0012__market_history.sql +0 -14
  171. package/templates/src/app/api/_platform/migrations/0013__users_profile.sql +0 -4
  172. package/templates/src/app/api/_platform/migrations/0014__reg_source_seq.mysql.sql +0 -9
  173. package/templates/src/app/api/_platform/migrations/0014__reg_source_seq.pg.sql +0 -7
  174. package/templates/src/app/api/_platform/migrations/0014__reg_source_seq.sql +0 -8
  175. package/templates/src/app/api/_platform/migrations/0015__tenant.mysql.sql +0 -12
  176. package/templates/src/app/api/_platform/migrations/0015__tenant.pg.sql +0 -11
  177. package/templates/src/app/api/_platform/migrations/0015__tenant.sql +0 -44
  178. package/templates/src/app/api/_platform/migrations/0016__org.mysql.sql +0 -41
  179. package/templates/src/app/api/_platform/migrations/0016__org.pg.sql +0 -40
  180. package/templates/src/app/api/_platform/migrations/0016__org.sql +0 -62
  181. package/templates/src/app/api/_platform/migrations/0017__users_employee_no.mysql.sql +0 -7
  182. package/templates/src/app/api/_platform/migrations/0017__users_employee_no.pg.sql +0 -4
  183. package/templates/src/app/api/_platform/migrations/0017__users_employee_no.sql +0 -8
  184. package/templates/src/app/api/_platform/migrations/0018__sys_role_title_key.mysql.sql +0 -3
  185. package/templates/src/app/api/_platform/migrations/0018__sys_role_title_key.pg.sql +0 -3
  186. package/templates/src/app/api/_platform/migrations/0018__sys_role_title_key.sql +0 -8
  187. package/templates/src/app/web/system/pages/login-methods/index.tsx +0 -30
@@ -870,6 +870,96 @@
870
870
  }
871
871
  }
872
872
  },
873
+ "/api/_platform/market/releases": {
874
+ "get": {
875
+ "operationId": "_platform_market_releases_get",
876
+ "summary": "GET api/_platform/market/releases",
877
+ "x-oj-file": "app/api/_platform/market/api.ts",
878
+ "tags": [
879
+ "_platform"
880
+ ],
881
+ "parameters": [
882
+ {
883
+ "name": "page",
884
+ "in": "query",
885
+ "required": false,
886
+ "schema": {
887
+ "type": "number",
888
+ "minimum": 1
889
+ }
890
+ },
891
+ {
892
+ "name": "limit",
893
+ "in": "query",
894
+ "required": false,
895
+ "schema": {
896
+ "type": "number",
897
+ "minimum": 1,
898
+ "maximum": 200
899
+ }
900
+ }
901
+ ],
902
+ "responses": {
903
+ "200": {
904
+ "description": "OK",
905
+ "x-oj-response-enforced": false,
906
+ "content": {
907
+ "application/json": {
908
+ "schema": {
909
+ "type": "object",
910
+ "required": [
911
+ "code",
912
+ "msg",
913
+ "data"
914
+ ],
915
+ "properties": {
916
+ "code": {
917
+ "type": "integer"
918
+ },
919
+ "msg": {
920
+ "type": "string"
921
+ },
922
+ "data": {
923
+ "type": "object",
924
+ "required": [
925
+ "list",
926
+ "total",
927
+ "page",
928
+ "size"
929
+ ],
930
+ "properties": {
931
+ "list": {
932
+ "type": "array",
933
+ "items": {
934
+ "type": "object",
935
+ "additionalProperties": true
936
+ }
937
+ },
938
+ "total": {
939
+ "type": "number"
940
+ },
941
+ "page": {
942
+ "type": "number"
943
+ },
944
+ "size": {
945
+ "type": "number"
946
+ },
947
+ "syncError": {
948
+ "type": [
949
+ "string",
950
+ "null"
951
+ ]
952
+ }
953
+ }
954
+ }
955
+ }
956
+ }
957
+ }
958
+ }
959
+ }
960
+ }
961
+ }
962
+ },
873
963
  "/api/_platform/org/departments": {
874
964
  "get": {
875
965
  "operationId": "_platform_org_departments_get",
@@ -4536,6 +4626,368 @@
4536
4626
  }
4537
4627
  }
4538
4628
  },
4629
+ "/api/publish/credential": {
4630
+ "get": {
4631
+ "operationId": "publish_credential_get",
4632
+ "summary": "GET api/publish/credential",
4633
+ "x-oj-file": "app/api/publish/api.ts",
4634
+ "tags": [
4635
+ "publish"
4636
+ ],
4637
+ "parameters": [
4638
+ {
4639
+ "name": "page",
4640
+ "in": "query",
4641
+ "required": false,
4642
+ "schema": {
4643
+ "type": "number",
4644
+ "minimum": 1
4645
+ }
4646
+ },
4647
+ {
4648
+ "name": "limit",
4649
+ "in": "query",
4650
+ "required": false,
4651
+ "schema": {
4652
+ "type": "number",
4653
+ "minimum": 1,
4654
+ "maximum": 200
4655
+ }
4656
+ },
4657
+ {
4658
+ "name": "tenant",
4659
+ "in": "query",
4660
+ "required": false,
4661
+ "schema": {
4662
+ "type": "string"
4663
+ }
4664
+ }
4665
+ ],
4666
+ "responses": {
4667
+ "200": {
4668
+ "description": "OK",
4669
+ "x-oj-response-enforced": false,
4670
+ "content": {
4671
+ "application/json": {
4672
+ "schema": {
4673
+ "type": "object",
4674
+ "required": [
4675
+ "code",
4676
+ "msg",
4677
+ "data"
4678
+ ],
4679
+ "properties": {
4680
+ "code": {
4681
+ "type": "integer"
4682
+ },
4683
+ "msg": {
4684
+ "type": "string"
4685
+ },
4686
+ "data": {
4687
+ "type": "object",
4688
+ "required": [
4689
+ "list",
4690
+ "total"
4691
+ ],
4692
+ "properties": {
4693
+ "list": {
4694
+ "type": "array",
4695
+ "items": {
4696
+ "type": "object",
4697
+ "required": [
4698
+ "id",
4699
+ "product",
4700
+ "key_id",
4701
+ "username",
4702
+ "token_hint",
4703
+ "status",
4704
+ "expires_at",
4705
+ "created_at"
4706
+ ],
4707
+ "properties": {
4708
+ "id": {
4709
+ "type": "number"
4710
+ },
4711
+ "product": {
4712
+ "type": "string"
4713
+ },
4714
+ "key_id": {
4715
+ "type": "string"
4716
+ },
4717
+ "username": {
4718
+ "type": "string"
4719
+ },
4720
+ "display_name": {
4721
+ "type": [
4722
+ "string",
4723
+ "null"
4724
+ ]
4725
+ },
4726
+ "token_hint": {
4727
+ "type": "string"
4728
+ },
4729
+ "status": {
4730
+ "type": "string",
4731
+ "enum": [
4732
+ "active",
4733
+ "used",
4734
+ "revoked",
4735
+ "expired"
4736
+ ]
4737
+ },
4738
+ "expires_at": {
4739
+ "type": "number"
4740
+ },
4741
+ "used_at": {
4742
+ "type": [
4743
+ "number",
4744
+ "null"
4745
+ ]
4746
+ },
4747
+ "created_at": {
4748
+ "type": "number"
4749
+ },
4750
+ "owner_tenant": {
4751
+ "type": "string"
4752
+ }
4753
+ }
4754
+ }
4755
+ },
4756
+ "total": {
4757
+ "type": "number"
4758
+ }
4759
+ }
4760
+ }
4761
+ }
4762
+ }
4763
+ }
4764
+ }
4765
+ }
4766
+ }
4767
+ },
4768
+ "post": {
4769
+ "operationId": "publish_credential_post",
4770
+ "summary": "POST api/publish/credential",
4771
+ "x-oj-file": "app/api/publish/api.ts",
4772
+ "tags": [
4773
+ "publish"
4774
+ ],
4775
+ "requestBody": {
4776
+ "required": true,
4777
+ "content": {
4778
+ "application/json": {
4779
+ "schema": {
4780
+ "type": "object",
4781
+ "required": [
4782
+ "product"
4783
+ ],
4784
+ "properties": {
4785
+ "product": {
4786
+ "type": "string"
4787
+ }
4788
+ }
4789
+ }
4790
+ }
4791
+ }
4792
+ },
4793
+ "responses": {
4794
+ "200": {
4795
+ "description": "OK",
4796
+ "x-oj-response-enforced": false,
4797
+ "content": {
4798
+ "application/json": {
4799
+ "schema": {
4800
+ "type": "object",
4801
+ "required": [
4802
+ "code",
4803
+ "msg",
4804
+ "data"
4805
+ ],
4806
+ "properties": {
4807
+ "code": {
4808
+ "type": "integer"
4809
+ },
4810
+ "msg": {
4811
+ "type": "string"
4812
+ },
4813
+ "data": {
4814
+ "type": "object",
4815
+ "required": [
4816
+ "token",
4817
+ "key_id",
4818
+ "product",
4819
+ "expires_at"
4820
+ ],
4821
+ "properties": {
4822
+ "token": {
4823
+ "type": "string"
4824
+ },
4825
+ "key_id": {
4826
+ "type": "string"
4827
+ },
4828
+ "product": {
4829
+ "type": "string"
4830
+ },
4831
+ "token_hint": {
4832
+ "type": "string"
4833
+ },
4834
+ "expires_at": {
4835
+ "type": "number"
4836
+ }
4837
+ }
4838
+ }
4839
+ }
4840
+ }
4841
+ }
4842
+ }
4843
+ }
4844
+ }
4845
+ }
4846
+ },
4847
+ "/api/publish/credential/revoke": {
4848
+ "post": {
4849
+ "operationId": "publish_credential_revoke_post",
4850
+ "summary": "POST api/publish/credential/revoke",
4851
+ "x-oj-file": "app/api/publish/api.ts",
4852
+ "tags": [
4853
+ "publish"
4854
+ ],
4855
+ "requestBody": {
4856
+ "required": true,
4857
+ "content": {
4858
+ "application/json": {
4859
+ "schema": {
4860
+ "type": "object",
4861
+ "required": [
4862
+ "id"
4863
+ ],
4864
+ "properties": {
4865
+ "id": {
4866
+ "type": "number"
4867
+ }
4868
+ }
4869
+ }
4870
+ }
4871
+ }
4872
+ },
4873
+ "responses": {
4874
+ "200": {
4875
+ "description": "OK",
4876
+ "x-oj-response-enforced": false,
4877
+ "content": {
4878
+ "application/json": {
4879
+ "schema": {
4880
+ "type": "object",
4881
+ "required": [
4882
+ "code",
4883
+ "msg",
4884
+ "data"
4885
+ ],
4886
+ "properties": {
4887
+ "code": {
4888
+ "type": "integer"
4889
+ },
4890
+ "msg": {
4891
+ "type": "string"
4892
+ },
4893
+ "data": {
4894
+ "type": "object",
4895
+ "required": [
4896
+ "ok"
4897
+ ],
4898
+ "properties": {
4899
+ "ok": {
4900
+ "type": "boolean"
4901
+ }
4902
+ }
4903
+ }
4904
+ }
4905
+ }
4906
+ }
4907
+ }
4908
+ }
4909
+ }
4910
+ }
4911
+ },
4912
+ "/api/publish/credential/exchange": {
4913
+ "post": {
4914
+ "operationId": "publish_credential_exchange_post",
4915
+ "summary": "POST api/publish/credential/exchange",
4916
+ "x-oj-file": "app/api/publish/api.ts",
4917
+ "tags": [
4918
+ "publish"
4919
+ ],
4920
+ "requestBody": {
4921
+ "required": true,
4922
+ "content": {
4923
+ "application/json": {
4924
+ "schema": {
4925
+ "type": "object",
4926
+ "required": [
4927
+ "token"
4928
+ ],
4929
+ "properties": {
4930
+ "token": {
4931
+ "type": "string"
4932
+ }
4933
+ }
4934
+ }
4935
+ }
4936
+ }
4937
+ },
4938
+ "responses": {
4939
+ "200": {
4940
+ "description": "OK",
4941
+ "x-oj-response-enforced": false,
4942
+ "content": {
4943
+ "application/json": {
4944
+ "schema": {
4945
+ "type": "object",
4946
+ "required": [
4947
+ "code",
4948
+ "msg",
4949
+ "data"
4950
+ ],
4951
+ "properties": {
4952
+ "code": {
4953
+ "type": "integer"
4954
+ },
4955
+ "msg": {
4956
+ "type": "string"
4957
+ },
4958
+ "data": {
4959
+ "type": "object",
4960
+ "required": [
4961
+ "key_id",
4962
+ "product",
4963
+ "username"
4964
+ ],
4965
+ "properties": {
4966
+ "key_id": {
4967
+ "type": "string"
4968
+ },
4969
+ "product": {
4970
+ "type": "string"
4971
+ },
4972
+ "username": {
4973
+ "type": "string"
4974
+ },
4975
+ "display_name": {
4976
+ "type": [
4977
+ "string",
4978
+ "null"
4979
+ ]
4980
+ }
4981
+ }
4982
+ }
4983
+ }
4984
+ }
4985
+ }
4986
+ }
4987
+ }
4988
+ }
4989
+ }
4990
+ },
4539
4991
  "/api/system/departments": {
4540
4992
  "get": {
4541
4993
  "operationId": "system_departments_get",
@@ -5325,7 +5777,8 @@
5325
5777
  "data": {
5326
5778
  "type": "object",
5327
5779
  "required": [
5328
- "methods"
5780
+ "methods",
5781
+ "site_title"
5329
5782
  ],
5330
5783
  "properties": {
5331
5784
  "methods": {
@@ -5333,6 +5786,9 @@
5333
5786
  "items": {
5334
5787
  "type": "string"
5335
5788
  }
5789
+ },
5790
+ "site_title": {
5791
+ "type": "string"
5336
5792
  }
5337
5793
  }
5338
5794
  }
@@ -6862,6 +7318,9 @@
6862
7318
  {
6863
7319
  "name": "personal-center"
6864
7320
  },
7321
+ {
7322
+ "name": "publish"
7323
+ },
6865
7324
  {
6866
7325
  "name": "system"
6867
7326
  },
@@ -0,0 +1,136 @@
1
+ // 安装补偿清单(P0 §3.5):锁后失败(registering/deploying_web/reloading/smoke)时,把站点恢复到
2
+ // 「装前代」状态——旧代继续服务,任务标 partial + 可重试。本模块是回滚的唯一入口(SRP:只负责
3
+ // 逆序回滚已落盘资产,不含装前校验/审计/终态文案),各资产回滚原语各自单一函数(OCP:新增资产
4
+ // 类型只需加一个原语 + 在此注册一步)。所有原语幂等(缺则 no-op),故补偿可安全被重试端点反复调用。
5
+ // 与 cancelCleanup 的区别(intentionally 不同):取消 = 回到装前且删版本目录;补偿 = 回到装前代
6
+ // 但**保留版本目录**供重试。两者共用 revertLock(lock.ts)不重复锁回退逻辑(DRY)。
7
+
8
+ import type { ReloadFace } from "./steps/reload";
9
+ import { atomicWriteText, fsFace, isMissingPath } from "./atomic";
10
+ import { revertLock } from "./lock";
11
+ import { removeModulesJsonEntry } from "./steps/deploy-web";
12
+ import { removeAnonymousPaths } from "./text-edit";
13
+ import { revertRegistrations } from "./uninstall";
14
+
15
+ /** 本仓 preview 派生文件名(与 cli preview-config.ts / installer.ts 逐字一致) */
16
+ const PREVIEW_CONFIG_NAME = ".ojm-preview.yaml";
17
+
18
+ /** 与 config 同目录的 preview 派生路径(无目录分隔符 = 同目录裸名);本地化避免与 installer.ts 循环依赖 */
19
+ function previewSiblingOf(configPath: string): string {
20
+ const cut = Math.max(configPath.lastIndexOf("/"), configPath.lastIndexOf("\\"));
21
+ return cut < 0 ? PREVIEW_CONFIG_NAME : `${configPath.slice(0, cut + 1)}${PREVIEW_CONFIG_NAME}`;
22
+ }
23
+
24
+ function isObj(v: unknown): v is Record<string, unknown> {
25
+ return typeof v === "object" && v !== null && !Array.isArray(v);
26
+ }
27
+
28
+ export interface CompensateInput {
29
+ /** 方案名 */
30
+ name: string
31
+ /** 本次安装版本 */
32
+ version: string
33
+ /** config.yaml 路径(缺省 "config.yaml") */
34
+ configPath: string
35
+ /** reloading 段真正新增的匿名路径(installer 已写入 req.deferredAnonymous);空 = 未接线,config 步 no-op */
36
+ deferredAnonymous: string[]
37
+ /** 站点 sharedRoot(锁/版本目录所在) */
38
+ sharedRoot: string
39
+ /** 站点 modules.json 路径 */
40
+ modulesJsonPath: string
41
+ /** runInstall 起始捕获的装前锁快照 */
42
+ lockBefore: Record<string, string>
43
+ /** 装前锁文件是否存在(首装 = false → 回退即删锁) */
44
+ lockExisted: boolean
45
+ /** 注入式 reload 面(与 reloadStage 同源) */
46
+ reload: ReloadFace
47
+ }
48
+
49
+ export interface CompensateStep {
50
+ step: string
51
+ ok: boolean
52
+ message: string
53
+ }
54
+
55
+ export interface CompensateResult {
56
+ /** 各步结果(逆序:config → lock → modules.json → db → reload) */
57
+ steps: CompensateStep[]
58
+ /** 是否全部成功(任一步失败即 false,但其余步仍尽力执行) */
59
+ allOk: boolean
60
+ }
61
+
62
+ /**
63
+ * 执行补偿回滚。每步独立 try/catch:单步失败记录进 steps 并继续其余步,最终 allOk 反映整体;
64
+ * 调用方据 allOk 决定 task 文案(失败步需在 message 中点名,便于运维定位)。
65
+ */
66
+ export async function compensate(input: CompensateInput): Promise<CompensateResult> {
67
+ const steps: CompensateStep[] = [];
68
+ const run = async (step: string, fn: () => Promise<void>): Promise<void> => {
69
+ try {
70
+ await fn();
71
+ steps.push({ step, ok: true, message: `${step}:已回滚到装前代` });
72
+ }
73
+ catch (e) {
74
+ steps.push({ step, ok: false, message: `${step}回滚失败:${String(e)}` });
75
+ }
76
+ };
77
+
78
+ const f = fsFace();
79
+
80
+ // 1. config 匿名移除(源 config + preview 派生,派生缺失即跳过)
81
+ await run("config.anonymous", async () => {
82
+ if (input.deferredAnonymous.length === 0) {
83
+ return;
84
+ }
85
+ for (const p of [input.configPath, previewSiblingOf(input.configPath)]) {
86
+ let content: string;
87
+ try {
88
+ content = new TextDecoder().decode(await f.readFile(p));
89
+ }
90
+ catch (e) {
91
+ if (isMissingPath(e)) {
92
+ continue;
93
+ }
94
+ throw e;
95
+ }
96
+ const { content: next, removed } = removeAnonymousPaths(content, input.deferredAnonymous);
97
+ if (removed.length > 0) {
98
+ await atomicWriteText(p, next);
99
+ }
100
+ }
101
+ });
102
+
103
+ // 2. lock 回写装前(首装则删锁;空锁拒启)
104
+ await run("lock", async () => {
105
+ await revertLock(input.sharedRoot, input.lockBefore, input.lockExisted);
106
+ });
107
+
108
+ // 3. modules.json 条目移除 + 断言(防并发写者插回)
109
+ await run("modules.json", async () => {
110
+ const { removed } = await removeModulesJsonEntry(input.name, { modulesJsonPath: input.modulesJsonPath });
111
+ if (!removed) {
112
+ return;
113
+ }
114
+ const list = JSON.parse(new TextDecoder().decode(await f.readFile(input.modulesJsonPath))) as unknown;
115
+ if (Array.isArray(list) && list.some(e => isObj(e) && e.name === input.name)) {
116
+ throw new Error("回滚后 modules.json 仍存在该模块条目(疑似并发写者插回)");
117
+ }
118
+ });
119
+
120
+ // 4. DB 注册回退(复用卸载事务:删 route + 级联清角色/权限)
121
+ await run("db.registrations", async () => {
122
+ await revertRegistrations(input.name);
123
+ });
124
+
125
+ // 5. reload 让旧代生效(best-effort 重同步活动代;抛错即记失败,目标=活动代回到装前态)
126
+ // 注:US-1 落地前上游仅按 config sha 判定——回退 config 会产出 applied(移除匿名),非 unchanged;
127
+ // US-1 落地后预期 unchanged===true。两种皆视为成功(只要未抛错)。
128
+ await run("reload", async () => {
129
+ const r = await input.reload.reloadConfig();
130
+ if (typeof r !== "object" || r === null || typeof r.unchanged !== "boolean") {
131
+ throw new Error("reloadConfig 返回形状违约(expected {unchanged:boolean,...})");
132
+ }
133
+ });
134
+
135
+ return { steps, allOk: steps.every(s => s.ok) };
136
+ }