@oj-module/cli 0.2.6 → 0.2.14

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 (169) hide show
  1. package/README.md +1 -1
  2. package/devkit/README.md +70 -24
  3. package/devkit/framework-dev.md +14 -5
  4. package/devkit/manual.md +28 -23
  5. package/devkit/module-dev-and-cdn-playground.md +197 -0
  6. package/devkit/sql-builder-missing-capabilities-pr.md +268 -0
  7. package/package.json +2 -2
  8. package/shell-dist/assets/runtime.js +130 -45
  9. package/shell-dist/index.html +2 -2
  10. package/shell-dist/versions.json +3 -3
  11. package/src/__tests__/build-backend.test.ts +64 -0
  12. package/src/__tests__/versions.test.ts +26 -0
  13. package/src/build.ts +9 -0
  14. package/src/bundle.ts +8 -5
  15. package/src/contract/__tests__/handler-scan.test.ts +29 -0
  16. package/src/contract/__tests__/market-client.integration.test.ts +170 -0
  17. package/src/contract/handler-scan.ts +35 -4
  18. package/src/dev.ts +10 -2
  19. package/src/index.ts +9 -3
  20. package/src/init.ts +24 -0
  21. package/src/lifecycle/__tests__/bundle.test.ts +3 -3
  22. package/src/market/__tests__/bootstrap.test.ts +204 -0
  23. package/src/market/__tests__/build-index.test.ts +154 -0
  24. package/src/market/__tests__/cdn-layout.test.ts +96 -0
  25. package/src/market/__tests__/failure-playbook.test.ts +33 -0
  26. package/src/market/__tests__/fixture.test.ts +48 -0
  27. package/src/market/__tests__/publish.test.ts +109 -0
  28. package/src/market/__tests__/report.test.ts +51 -0
  29. package/src/market/__tests__/setup.test.ts +114 -0
  30. package/src/market/__tests__/verify.test.ts +111 -0
  31. package/src/market/bootstrap.ts +255 -0
  32. package/src/market/build-index.ts +159 -0
  33. package/src/market/cdn-layout.ts +122 -0
  34. package/src/market/command.ts +139 -0
  35. package/src/market/failure-playbook.ts +57 -0
  36. package/src/market/fixture.ts +138 -0
  37. package/src/market/index-builder.ts +76 -0
  38. package/src/market/publish.ts +156 -0
  39. package/src/market/report.ts +67 -0
  40. package/src/market/scan.ts +99 -0
  41. package/src/market/setup.ts +144 -0
  42. package/src/market/trial.ts +121 -0
  43. package/src/market/verify.ts +298 -0
  44. package/src/market/walkthrough.ts +506 -0
  45. package/src/oj.ts +3 -1
  46. package/src/preview-config.ts +177 -0
  47. package/src/preview.ts +106 -56
  48. package/src/sign.ts +21 -6
  49. package/src/usage.ts +22 -2
  50. package/src/vendor.ts +4 -2
  51. package/src/versions.ts +28 -0
  52. package/templates/api/.ojm-api-exempt.json +6 -2
  53. package/templates/api/config.yaml +24 -2
  54. package/templates/api/src/_platform/README.md +31 -0
  55. package/templates/api/src/_platform/_lifecycle/atomic.ts +1 -1
  56. package/templates/api/src/_platform/_lifecycle/history.ts +10 -5
  57. package/templates/api/src/_platform/_lifecycle/installer.ts +4 -4
  58. package/templates/api/src/_platform/_lifecycle/sha384.ts +1 -1
  59. package/templates/api/src/_platform/_lifecycle/steps/download.ts +1 -1
  60. package/templates/api/src/_platform/_lifecycle/steps/extract.ts +8 -8
  61. package/templates/api/src/_platform/_lifecycle/steps/register.ts +57 -29
  62. package/templates/api/src/_platform/_lifecycle/trust.ts +1 -1
  63. package/templates/api/src/_platform/_lifecycle/uninstall.ts +29 -56
  64. package/templates/api/src/_platform/_lifecycle/verify-checks.ts +2 -2
  65. package/templates/api/src/_platform/_shared/service/{contacts.ts → domain/contacts.ts} +20 -13
  66. package/templates/api/src/_platform/_shared/service/{roles.ts → domain/roles.ts} +18 -19
  67. package/templates/api/src/_platform/_shared/service/{settings.ts → domain/settings.ts} +6 -6
  68. package/templates/api/src/_platform/_shared/service/{solution-perms.ts → domain/solution-perms.ts} +25 -22
  69. package/templates/api/src/_platform/_shared/service/{users.ts → domain/users.ts} +20 -26
  70. package/templates/api/src/_platform/_shared/service/{access.ts → infra/access.ts} +5 -8
  71. package/templates/api/src/_platform/_shared/service/{audit.ts → infra/audit.ts} +26 -26
  72. package/templates/api/src/_platform/_shared/service/infra/oplog.ts +40 -0
  73. package/templates/api/src/_platform/_shared/service/{query.ts → infra/query.ts} +18 -0
  74. package/templates/api/src/_platform/_shared/service/{rate.ts → infra/rate.ts} +16 -13
  75. package/templates/api/src/_platform/_shared/site-facade.ts +1 -1
  76. package/templates/api/src/_platform/contacts/api.ts +2 -2
  77. package/templates/api/src/_platform/contacts/detail/api.ts +2 -2
  78. package/templates/api/src/_platform/fixtures/l1-test-user.sql +13 -0
  79. package/templates/api/src/_platform/manifest.yaml +4 -1
  80. package/templates/api/src/_platform/market/api.ts +54 -16
  81. package/templates/api/src/_platform/migrations/0013__users_profile.sql +4 -0
  82. package/templates/api/src/_platform/schema.yaml +26 -0
  83. package/templates/api/src/_platform/solutions/api.ts +13 -12
  84. package/templates/api/src/auth/_shared/ldap-login.ts +11 -7
  85. package/templates/api/src/auth/_shared/login-throttle.ts +2 -2
  86. package/templates/api/src/auth/_shared/session.ts +26 -22
  87. package/templates/api/src/auth/api.ts +1 -1
  88. package/templates/api/src/demo/todos/api.ts +8 -8
  89. package/templates/api/src/home/line/api.ts +4 -4
  90. package/templates/api/src/home/pie/api.ts +4 -4
  91. package/templates/api/src/notification/_shared/notify.ts +97 -57
  92. package/templates/api/src/notification/api.ts +1 -1
  93. package/templates/api/src/notification/manifest.yaml +1 -0
  94. package/templates/api/src/notification/migrations/0004__notifications_broadcast_hidden.sql +12 -0
  95. package/templates/api/src/notification/schema.yaml +7 -0
  96. package/templates/api/src/notification/seed.sql +5 -4
  97. package/templates/api/src/personal-center/profile/api.ts +63 -0
  98. package/templates/api/src/personal-center/upload/api.ts +1 -1
  99. package/templates/api/src/system/login-methods/api.ts +1 -1
  100. package/templates/api/src/system/oplog/api.ts +3 -3
  101. package/templates/api/src/system/permissions/api.ts +2 -2
  102. package/templates/api/src/system/roles/api.ts +2 -2
  103. package/templates/api/src/system/roles/bindings/api.ts +2 -2
  104. package/templates/api/src/system/settings/api.ts +2 -2
  105. package/templates/api/src/system/users/api.ts +2 -2
  106. package/templates/api/src/system/users/forbidden/api.ts +2 -2
  107. package/templates/api/src/system/users/password/api.ts +2 -2
  108. package/templates/api/src/system/users/roles/api.ts +2 -2
  109. package/templates/api/src/web/user-info/api.ts +4 -5
  110. package/templates/api/tests/auth-session.spec.ts +1 -1
  111. package/templates/api/tests/auth-throttle.spec.ts +1 -1
  112. package/templates/api/tests/fixture.ts +8 -16
  113. package/templates/api/tests/guard.spec.ts +1 -1
  114. package/templates/api/tests/l1-builder.test.ts +91 -0
  115. package/templates/api/tests/lifecycle/installer.spec.ts +1 -4
  116. package/templates/api/tests/lifecycle/market-api.spec.ts +2 -4
  117. package/templates/api/tests/lifecycle/steps-fs.spec.ts +5 -8
  118. package/templates/api/tests/lifecycle/trust.spec.ts +1 -1
  119. package/templates/api/tests/lifecycle/uninstall.spec.ts +29 -89
  120. package/templates/api/tests/query-utils.spec.ts +85 -1
  121. package/templates/api/tests/rbac-audit.spec.ts +1 -1
  122. package/templates/api/tests/rbac-contacts.spec.ts +2 -2
  123. package/templates/api/tests/rbac-guard.spec.ts +1 -1
  124. package/templates/api/tests/rbac-roles.spec.ts +2 -2
  125. package/templates/api/tests/rbac-settings.spec.ts +66 -21
  126. package/templates/api/tests/rbac-solution-perms.spec.ts +1 -1
  127. package/templates/api/tests/rbac-users.spec.ts +1 -1
  128. package/templates/api/tsconfig.json +8 -0
  129. package/templates/cdn/README.md +48 -0
  130. package/templates/env.d.ts +2 -0
  131. package/templates/global.d.ts +850 -0
  132. package/templates/init.include.yaml +14 -2
  133. package/templates/logs/task-events.jsonl +0 -0
  134. package/templates/openapi.json +580 -23
  135. package/templates/package.json +2 -1
  136. package/templates/web/src/_platform/__client/api.schemas.ts +97 -0
  137. package/templates/web/src/_platform/__client/api.ts +152 -39
  138. package/templates/web/src/notification/entry.ts +46 -9
  139. package/templates/web/src/notification/locales/en-US.json +19 -0
  140. package/templates/web/src/notification/locales/zh-CN.json +19 -0
  141. package/templates/web/src/notification/pages/center/index.tsx +131 -0
  142. package/templates/web/src/oj-market/__tests__/CardGrid.test.tsx +19 -0
  143. package/templates/web/src/oj-market/__tests__/InstallDialog.test.tsx +3 -0
  144. package/templates/web/src/oj-market/__tests__/RollbackDialog.test.tsx +1 -0
  145. package/templates/web/src/oj-market/__tests__/marketClient.fake.ts +1 -0
  146. package/templates/web/src/oj-market/api/client.ts +5 -105
  147. package/templates/web/src/oj-market/api/defaultClient.ts +111 -5
  148. package/templates/web/src/oj-market/components/CardGrid.tsx +4 -1
  149. package/templates/web/src/oj-market/components/CardItem.tsx +9 -5
  150. package/templates/web/src/oj-market/components/DetailDrawer.tsx +7 -3
  151. package/templates/web/src/oj-market/components/InstallDialog.tsx +1 -1
  152. package/templates/web/src/oj-market/entry.ts +8 -2
  153. package/templates/web/src/oj-market/hooks/useMarket.ts +4 -1
  154. package/templates/web/src/oj-market/locales/en-US.json +2 -1
  155. package/templates/web/src/oj-market/locales/zh-CN.json +2 -1
  156. package/templates/web/src/oj-market/pages/MarketApp.tsx +16 -1
  157. package/templates/web/src/personal-center/__client/api.schemas.ts +9 -0
  158. package/templates/web/src/personal-center/__client/api.ts +25 -1
  159. package/templates/web/src/personal-center/entry.ts +5 -0
  160. package/templates/web/src/personal-center/pages/my-profile/index.tsx +25 -3
  161. package/templates/web/src/system/entry.ts +2 -1
  162. package/templates/web.config.ts +13 -10
  163. package/vendor/host-versions.json +3 -3
  164. package/templates/api/src/_platform/_shared/service/oplog.ts +0 -47
  165. package/templates/api/src/notifications/api.ts +0 -32
  166. package/templates/api/src/notifications/manifest.yaml +0 -5
  167. package/templates/web/src/notifications/__client/api.schemas.ts +0 -8
  168. package/templates/web/src/notifications/__client/api.ts +0 -80
  169. /package/templates/api/src/_platform/_shared/service/{guard.ts → infra/guard.ts} +0 -0
@@ -8,7 +8,8 @@
8
8
  "build": "ojm build",
9
9
  "preview": "ojm preview",
10
10
  "info": "ojm info",
11
- "typecheck": "tsc --noEmit -p tsconfig.json"
11
+ "typecheck": "tsc --noEmit -p tsconfig.json",
12
+ "typecheck:api": "tsc --noEmit -p api/tsconfig.json"
12
13
  },
13
14
  "devDependencies": {
14
15
  "@ant-design/cssinjs": "catalog:",
@@ -4,5 +4,102 @@
4
4
  import { z } from "@oj-module/runtime";
5
5
 
6
6
  export const schemas = {
7
+ "platformMarketInstallPost": {
8
+ body: z.object({
9
+ "source": z.enum(["cdn", "file"]),
10
+ "name": z.string(),
11
+ "version": z.string().nullable().optional()
12
+ }),
13
+ data: z.object({
14
+ "task_id": z.string().optional()
15
+ }).catchall(z.unknown()),
16
+ },
17
+ "platformMarketInstallCancelPost": {
18
+ body: z.object({
19
+ "name": z.string()
20
+ }),
21
+ data: z.object({
22
+ "ok": z.boolean().optional(),
23
+ "name": z.string().optional(),
24
+ "requested": z.boolean().optional()
25
+ }).catchall(z.unknown()),
26
+ },
27
+ "platformMarketTaskGet": {
28
+ query: z.object({
29
+ "id": z.string()
30
+ }),
31
+ data: z.object({
7
32
 
33
+ }).catchall(z.unknown()),
34
+ },
35
+ "platformMarketEnablePost": {
36
+ body: z.object({
37
+ "name": z.string(),
38
+ "enabled": z.boolean()
39
+ }),
40
+ data: z.object({
41
+
42
+ }).catchall(z.unknown()),
43
+ },
44
+ "platformMarketMetaGet": {
45
+ data: z.object({
46
+ "apiVersion": z.string().optional()
47
+ }).catchall(z.unknown()),
48
+ },
49
+ "platformMarketTrustGet": {
50
+ data: z.object({
51
+
52
+ }).catchall(z.unknown()),
53
+ },
54
+ "platformMarketTrustPost": {
55
+ body: z.object({
56
+ "task_id": z.string()
57
+ }),
58
+ data: z.object({
59
+
60
+ }).catchall(z.unknown()),
61
+ },
62
+ "platformMarketTrustKeyPost": {
63
+ body: z.object({
64
+ "key_id": z.string(),
65
+ "public_key": z.string()
66
+ }),
67
+ data: z.object({
68
+
69
+ }).catchall(z.unknown()),
70
+ },
71
+ "platformMarketTrustKeyDelete": {
72
+ query: z.object({
73
+ "key_id": z.string()
74
+ }),
75
+ data: z.object({
76
+
77
+ }).catchall(z.unknown()),
78
+ },
79
+ "platformMarketIndexGet": {
80
+ data: z.array(z.object({
81
+
82
+ }).catchall(z.unknown())),
83
+ },
84
+ "platformMarketUninstallImpactGet": {
85
+ query: z.object({
86
+ "name": z.string()
87
+ }),
88
+ data: z.object({
89
+
90
+ }).catchall(z.unknown()),
91
+ },
92
+ "platformMarketUninstallPost": {
93
+ body: z.object({
94
+ "name": z.string()
95
+ }),
96
+ data: z.object({
97
+
98
+ }).catchall(z.unknown()),
99
+ },
100
+ "platformMarketHistoryGet": {
101
+ data: z.array(z.object({
102
+
103
+ }).catchall(z.unknown())),
104
+ },
8
105
  };
@@ -94,14 +94,23 @@ export async function platformContactsDetailGet(): Promise<unknown> {
94
94
  }
95
95
  }
96
96
 
97
- export async function platformMarketInstallPost(): Promise<unknown> {
97
+ export type PlatformMarketInstallPostBody = z.input<(typeof schemas)["platformMarketInstallPost"]["body"]>;
98
+ export type PlatformMarketInstallPostData = z.infer<(typeof schemas)["platformMarketInstallPost"]["data"]>;
99
+
100
+ export async function platformMarketInstallPost(body: PlatformMarketInstallPostBody): Promise<PlatformMarketInstallPostData> {
98
101
  const client = ensureReq();
99
102
  try {
100
- const env = await client.post(`_platform/market/install`).json<OjEnvelope<unknown>>();
103
+ const env = await client.post(`_platform/market/install`, { json: body }).json<OjEnvelope<PlatformMarketInstallPostData>>();
101
104
  // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
102
105
  if (typeof env.code === "number" && env.code !== 0)
103
106
  throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
104
- const data = env.data as unknown;
107
+ const data = env.data as PlatformMarketInstallPostData;
108
+ if (import.meta.env.DEV) {
109
+ const { schemas } = await import("./api.schemas");
110
+ const r = schemas["platformMarketInstallPost"].data.safeParse(data);
111
+ if (!r.success)
112
+ throw new ContractApiError(-1, `[契约违例] platformMarketInstallPost 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
113
+ }
105
114
  return data;
106
115
  }
107
116
  catch (e) {
@@ -109,14 +118,23 @@ export async function platformMarketInstallPost(): Promise<unknown> {
109
118
  }
110
119
  }
111
120
 
112
- export async function platformMarketInstallCancelPost(): Promise<unknown> {
121
+ export type PlatformMarketInstallCancelPostBody = z.input<(typeof schemas)["platformMarketInstallCancelPost"]["body"]>;
122
+ export type PlatformMarketInstallCancelPostData = z.infer<(typeof schemas)["platformMarketInstallCancelPost"]["data"]>;
123
+
124
+ export async function platformMarketInstallCancelPost(body: PlatformMarketInstallCancelPostBody): Promise<PlatformMarketInstallCancelPostData> {
113
125
  const client = ensureReq();
114
126
  try {
115
- const env = await client.post(`_platform/market/install/cancel`).json<OjEnvelope<unknown>>();
127
+ const env = await client.post(`_platform/market/install/cancel`, { json: body }).json<OjEnvelope<PlatformMarketInstallCancelPostData>>();
116
128
  // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
117
129
  if (typeof env.code === "number" && env.code !== 0)
118
130
  throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
119
- const data = env.data as unknown;
131
+ const data = env.data as PlatformMarketInstallCancelPostData;
132
+ if (import.meta.env.DEV) {
133
+ const { schemas } = await import("./api.schemas");
134
+ const r = schemas["platformMarketInstallCancelPost"].data.safeParse(data);
135
+ if (!r.success)
136
+ throw new ContractApiError(-1, `[契约违例] platformMarketInstallCancelPost 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
137
+ }
120
138
  return data;
121
139
  }
122
140
  catch (e) {
@@ -124,14 +142,23 @@ export async function platformMarketInstallCancelPost(): Promise<unknown> {
124
142
  }
125
143
  }
126
144
 
127
- export async function platformMarketTaskGet(): Promise<unknown> {
145
+ export type PlatformMarketTaskGetQuery = z.input<(typeof schemas)["platformMarketTaskGet"]["query"]>;
146
+ export type PlatformMarketTaskGetData = z.infer<(typeof schemas)["platformMarketTaskGet"]["data"]>;
147
+
148
+ export async function platformMarketTaskGet(query: PlatformMarketTaskGetQuery): Promise<PlatformMarketTaskGetData> {
128
149
  const client = ensureReq();
129
150
  try {
130
- const env = await client.get(`_platform/market/task`).json<OjEnvelope<unknown>>();
151
+ const env = await client.get(`_platform/market/task`, { searchParams: query as Record<string, string | number | boolean> }).json<OjEnvelope<PlatformMarketTaskGetData>>();
131
152
  // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
132
153
  if (typeof env.code === "number" && env.code !== 0)
133
154
  throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
134
- const data = env.data as unknown;
155
+ const data = env.data as PlatformMarketTaskGetData;
156
+ if (import.meta.env.DEV) {
157
+ const { schemas } = await import("./api.schemas");
158
+ const r = schemas["platformMarketTaskGet"].data.safeParse(data);
159
+ if (!r.success)
160
+ throw new ContractApiError(-1, `[契约违例] platformMarketTaskGet 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
161
+ }
135
162
  return data;
136
163
  }
137
164
  catch (e) {
@@ -139,14 +166,23 @@ export async function platformMarketTaskGet(): Promise<unknown> {
139
166
  }
140
167
  }
141
168
 
142
- export async function platformMarketEnablePost(): Promise<unknown> {
169
+ export type PlatformMarketEnablePostBody = z.input<(typeof schemas)["platformMarketEnablePost"]["body"]>;
170
+ export type PlatformMarketEnablePostData = z.infer<(typeof schemas)["platformMarketEnablePost"]["data"]>;
171
+
172
+ export async function platformMarketEnablePost(body: PlatformMarketEnablePostBody): Promise<PlatformMarketEnablePostData> {
143
173
  const client = ensureReq();
144
174
  try {
145
- const env = await client.post(`_platform/market/enable`).json<OjEnvelope<unknown>>();
175
+ const env = await client.post(`_platform/market/enable`, { json: body }).json<OjEnvelope<PlatformMarketEnablePostData>>();
146
176
  // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
147
177
  if (typeof env.code === "number" && env.code !== 0)
148
178
  throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
149
- const data = env.data as unknown;
179
+ const data = env.data as PlatformMarketEnablePostData;
180
+ if (import.meta.env.DEV) {
181
+ const { schemas } = await import("./api.schemas");
182
+ const r = schemas["platformMarketEnablePost"].data.safeParse(data);
183
+ if (!r.success)
184
+ throw new ContractApiError(-1, `[契约违例] platformMarketEnablePost 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
185
+ }
150
186
  return data;
151
187
  }
152
188
  catch (e) {
@@ -154,14 +190,22 @@ export async function platformMarketEnablePost(): Promise<unknown> {
154
190
  }
155
191
  }
156
192
 
157
- export async function platformMarketMetaGet(): Promise<unknown> {
193
+ export type PlatformMarketMetaGetData = z.infer<(typeof schemas)["platformMarketMetaGet"]["data"]>;
194
+
195
+ export async function platformMarketMetaGet(): Promise<PlatformMarketMetaGetData> {
158
196
  const client = ensureReq();
159
197
  try {
160
- const env = await client.get(`_platform/market/meta`).json<OjEnvelope<unknown>>();
198
+ const env = await client.get(`_platform/market/meta`).json<OjEnvelope<PlatformMarketMetaGetData>>();
161
199
  // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
162
200
  if (typeof env.code === "number" && env.code !== 0)
163
201
  throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
164
- const data = env.data as unknown;
202
+ const data = env.data as PlatformMarketMetaGetData;
203
+ if (import.meta.env.DEV) {
204
+ const { schemas } = await import("./api.schemas");
205
+ const r = schemas["platformMarketMetaGet"].data.safeParse(data);
206
+ if (!r.success)
207
+ throw new ContractApiError(-1, `[契约违例] platformMarketMetaGet 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
208
+ }
165
209
  return data;
166
210
  }
167
211
  catch (e) {
@@ -169,14 +213,22 @@ export async function platformMarketMetaGet(): Promise<unknown> {
169
213
  }
170
214
  }
171
215
 
172
- export async function platformMarketTrustGet(): Promise<unknown> {
216
+ export type PlatformMarketTrustGetData = z.infer<(typeof schemas)["platformMarketTrustGet"]["data"]>;
217
+
218
+ export async function platformMarketTrustGet(): Promise<PlatformMarketTrustGetData> {
173
219
  const client = ensureReq();
174
220
  try {
175
- const env = await client.get(`_platform/market/trust`).json<OjEnvelope<unknown>>();
221
+ const env = await client.get(`_platform/market/trust`).json<OjEnvelope<PlatformMarketTrustGetData>>();
176
222
  // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
177
223
  if (typeof env.code === "number" && env.code !== 0)
178
224
  throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
179
- const data = env.data as unknown;
225
+ const data = env.data as PlatformMarketTrustGetData;
226
+ if (import.meta.env.DEV) {
227
+ const { schemas } = await import("./api.schemas");
228
+ const r = schemas["platformMarketTrustGet"].data.safeParse(data);
229
+ if (!r.success)
230
+ throw new ContractApiError(-1, `[契约违例] platformMarketTrustGet 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
231
+ }
180
232
  return data;
181
233
  }
182
234
  catch (e) {
@@ -184,14 +236,23 @@ export async function platformMarketTrustGet(): Promise<unknown> {
184
236
  }
185
237
  }
186
238
 
187
- export async function platformMarketTrustPost(): Promise<unknown> {
239
+ export type PlatformMarketTrustPostBody = z.input<(typeof schemas)["platformMarketTrustPost"]["body"]>;
240
+ export type PlatformMarketTrustPostData = z.infer<(typeof schemas)["platformMarketTrustPost"]["data"]>;
241
+
242
+ export async function platformMarketTrustPost(body: PlatformMarketTrustPostBody): Promise<PlatformMarketTrustPostData> {
188
243
  const client = ensureReq();
189
244
  try {
190
- const env = await client.post(`_platform/market/trust`).json<OjEnvelope<unknown>>();
245
+ const env = await client.post(`_platform/market/trust`, { json: body }).json<OjEnvelope<PlatformMarketTrustPostData>>();
191
246
  // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
192
247
  if (typeof env.code === "number" && env.code !== 0)
193
248
  throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
194
- const data = env.data as unknown;
249
+ const data = env.data as PlatformMarketTrustPostData;
250
+ if (import.meta.env.DEV) {
251
+ const { schemas } = await import("./api.schemas");
252
+ const r = schemas["platformMarketTrustPost"].data.safeParse(data);
253
+ if (!r.success)
254
+ throw new ContractApiError(-1, `[契约违例] platformMarketTrustPost 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
255
+ }
195
256
  return data;
196
257
  }
197
258
  catch (e) {
@@ -199,14 +260,23 @@ export async function platformMarketTrustPost(): Promise<unknown> {
199
260
  }
200
261
  }
201
262
 
202
- export async function platformMarketTrustKeyPost(): Promise<unknown> {
263
+ export type PlatformMarketTrustKeyPostBody = z.input<(typeof schemas)["platformMarketTrustKeyPost"]["body"]>;
264
+ export type PlatformMarketTrustKeyPostData = z.infer<(typeof schemas)["platformMarketTrustKeyPost"]["data"]>;
265
+
266
+ export async function platformMarketTrustKeyPost(body: PlatformMarketTrustKeyPostBody): Promise<PlatformMarketTrustKeyPostData> {
203
267
  const client = ensureReq();
204
268
  try {
205
- const env = await client.post(`_platform/market/trust/key`).json<OjEnvelope<unknown>>();
269
+ const env = await client.post(`_platform/market/trust/key`, { json: body }).json<OjEnvelope<PlatformMarketTrustKeyPostData>>();
206
270
  // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
207
271
  if (typeof env.code === "number" && env.code !== 0)
208
272
  throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
209
- const data = env.data as unknown;
273
+ const data = env.data as PlatformMarketTrustKeyPostData;
274
+ if (import.meta.env.DEV) {
275
+ const { schemas } = await import("./api.schemas");
276
+ const r = schemas["platformMarketTrustKeyPost"].data.safeParse(data);
277
+ if (!r.success)
278
+ throw new ContractApiError(-1, `[契约违例] platformMarketTrustKeyPost 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
279
+ }
210
280
  return data;
211
281
  }
212
282
  catch (e) {
@@ -214,14 +284,23 @@ export async function platformMarketTrustKeyPost(): Promise<unknown> {
214
284
  }
215
285
  }
216
286
 
217
- export async function platformMarketTrustKeyDelete(): Promise<unknown> {
287
+ export type PlatformMarketTrustKeyDeleteQuery = z.input<(typeof schemas)["platformMarketTrustKeyDelete"]["query"]>;
288
+ export type PlatformMarketTrustKeyDeleteData = z.infer<(typeof schemas)["platformMarketTrustKeyDelete"]["data"]>;
289
+
290
+ export async function platformMarketTrustKeyDelete(query: PlatformMarketTrustKeyDeleteQuery): Promise<PlatformMarketTrustKeyDeleteData> {
218
291
  const client = ensureReq();
219
292
  try {
220
- const env = await client.delete(`_platform/market/trust/key`).json<OjEnvelope<unknown>>();
293
+ const env = await client.delete(`_platform/market/trust/key`, { searchParams: query as Record<string, string | number | boolean> }).json<OjEnvelope<PlatformMarketTrustKeyDeleteData>>();
221
294
  // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
222
295
  if (typeof env.code === "number" && env.code !== 0)
223
296
  throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
224
- const data = env.data as unknown;
297
+ const data = env.data as PlatformMarketTrustKeyDeleteData;
298
+ if (import.meta.env.DEV) {
299
+ const { schemas } = await import("./api.schemas");
300
+ const r = schemas["platformMarketTrustKeyDelete"].data.safeParse(data);
301
+ if (!r.success)
302
+ throw new ContractApiError(-1, `[契约违例] platformMarketTrustKeyDelete 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
303
+ }
225
304
  return data;
226
305
  }
227
306
  catch (e) {
@@ -229,14 +308,22 @@ export async function platformMarketTrustKeyDelete(): Promise<unknown> {
229
308
  }
230
309
  }
231
310
 
232
- export async function platformMarketIndexGet(): Promise<unknown> {
311
+ export type PlatformMarketIndexGetData = z.infer<(typeof schemas)["platformMarketIndexGet"]["data"]>;
312
+
313
+ export async function platformMarketIndexGet(): Promise<PlatformMarketIndexGetData> {
233
314
  const client = ensureReq();
234
315
  try {
235
- const env = await client.get(`_platform/market/index`).json<OjEnvelope<unknown>>();
316
+ const env = await client.get(`_platform/market/index`).json<OjEnvelope<PlatformMarketIndexGetData>>();
236
317
  // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
237
318
  if (typeof env.code === "number" && env.code !== 0)
238
319
  throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
239
- const data = env.data as unknown;
320
+ const data = env.data as PlatformMarketIndexGetData;
321
+ if (import.meta.env.DEV) {
322
+ const { schemas } = await import("./api.schemas");
323
+ const r = schemas["platformMarketIndexGet"].data.safeParse(data);
324
+ if (!r.success)
325
+ throw new ContractApiError(-1, `[契约违例] platformMarketIndexGet 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
326
+ }
240
327
  return data;
241
328
  }
242
329
  catch (e) {
@@ -244,14 +331,23 @@ export async function platformMarketIndexGet(): Promise<unknown> {
244
331
  }
245
332
  }
246
333
 
247
- export async function platformMarketUninstallImpactGet(): Promise<unknown> {
334
+ export type PlatformMarketUninstallImpactGetQuery = z.input<(typeof schemas)["platformMarketUninstallImpactGet"]["query"]>;
335
+ export type PlatformMarketUninstallImpactGetData = z.infer<(typeof schemas)["platformMarketUninstallImpactGet"]["data"]>;
336
+
337
+ export async function platformMarketUninstallImpactGet(query: PlatformMarketUninstallImpactGetQuery): Promise<PlatformMarketUninstallImpactGetData> {
248
338
  const client = ensureReq();
249
339
  try {
250
- const env = await client.get(`_platform/market/uninstall-impact`).json<OjEnvelope<unknown>>();
340
+ const env = await client.get(`_platform/market/uninstall-impact`, { searchParams: query as Record<string, string | number | boolean> }).json<OjEnvelope<PlatformMarketUninstallImpactGetData>>();
251
341
  // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
252
342
  if (typeof env.code === "number" && env.code !== 0)
253
343
  throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
254
- const data = env.data as unknown;
344
+ const data = env.data as PlatformMarketUninstallImpactGetData;
345
+ if (import.meta.env.DEV) {
346
+ const { schemas } = await import("./api.schemas");
347
+ const r = schemas["platformMarketUninstallImpactGet"].data.safeParse(data);
348
+ if (!r.success)
349
+ throw new ContractApiError(-1, `[契约违例] platformMarketUninstallImpactGet 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
350
+ }
255
351
  return data;
256
352
  }
257
353
  catch (e) {
@@ -259,14 +355,23 @@ export async function platformMarketUninstallImpactGet(): Promise<unknown> {
259
355
  }
260
356
  }
261
357
 
262
- export async function platformMarketUninstallPost(): Promise<unknown> {
358
+ export type PlatformMarketUninstallPostBody = z.input<(typeof schemas)["platformMarketUninstallPost"]["body"]>;
359
+ export type PlatformMarketUninstallPostData = z.infer<(typeof schemas)["platformMarketUninstallPost"]["data"]>;
360
+
361
+ export async function platformMarketUninstallPost(body: PlatformMarketUninstallPostBody): Promise<PlatformMarketUninstallPostData> {
263
362
  const client = ensureReq();
264
363
  try {
265
- const env = await client.post(`_platform/market/uninstall`).json<OjEnvelope<unknown>>();
364
+ const env = await client.post(`_platform/market/uninstall`, { json: body }).json<OjEnvelope<PlatformMarketUninstallPostData>>();
266
365
  // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
267
366
  if (typeof env.code === "number" && env.code !== 0)
268
367
  throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
269
- const data = env.data as unknown;
368
+ const data = env.data as PlatformMarketUninstallPostData;
369
+ if (import.meta.env.DEV) {
370
+ const { schemas } = await import("./api.schemas");
371
+ const r = schemas["platformMarketUninstallPost"].data.safeParse(data);
372
+ if (!r.success)
373
+ throw new ContractApiError(-1, `[契约违例] platformMarketUninstallPost 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
374
+ }
270
375
  return data;
271
376
  }
272
377
  catch (e) {
@@ -274,14 +379,22 @@ export async function platformMarketUninstallPost(): Promise<unknown> {
274
379
  }
275
380
  }
276
381
 
277
- export async function platformMarketHistoryGet(): Promise<unknown> {
382
+ export type PlatformMarketHistoryGetData = z.infer<(typeof schemas)["platformMarketHistoryGet"]["data"]>;
383
+
384
+ export async function platformMarketHistoryGet(): Promise<PlatformMarketHistoryGetData> {
278
385
  const client = ensureReq();
279
386
  try {
280
- const env = await client.get(`_platform/market/history`).json<OjEnvelope<unknown>>();
387
+ const env = await client.get(`_platform/market/history`).json<OjEnvelope<PlatformMarketHistoryGetData>>();
281
388
  // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
282
389
  if (typeof env.code === "number" && env.code !== 0)
283
390
  throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
284
- const data = env.data as unknown;
391
+ const data = env.data as PlatformMarketHistoryGetData;
392
+ if (import.meta.env.DEV) {
393
+ const { schemas } = await import("./api.schemas");
394
+ const r = schemas["platformMarketHistoryGet"].data.safeParse(data);
395
+ if (!r.success)
396
+ throw new ContractApiError(-1, `[契约违例] platformMarketHistoryGet 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
397
+ }
285
398
  return data;
286
399
  }
287
400
  catch (e) {
@@ -1,23 +1,60 @@
1
- import type { NotificationsApiProvider } from "@oj-module/runtime";
1
+ import type { AppRouteRecordRaw, NotificationsApiProvider } from "@oj-module/runtime";
2
2
 
3
+ import { BellOutlined } from "@ant-design/icons";
3
4
  import { defineModule } from "@oj-module/runtime";
4
5
 
6
+ import { createElement, lazy } from "react";
7
+
5
8
  import { createNotificationClient } from "./__client/api";
6
9
 
10
+ const NotificationCenter = lazy(() => import("./pages/center"));
11
+
12
+ /**
13
+ * 通知中心页(N3):全量消息 + 类型 Tab,铃铛弹层「查看全部」跳转至此。
14
+ * hideInMenu——入口在铃铛,不占侧边导航。
15
+ * 布局挂父路由 handle(resolveRouteLayouts 只给「无 Component 有 children」的
16
+ * 父路由注入 layout,页面组件写父级上布局会被忽略、裸渲染无 chrome)。
17
+ */
18
+ const routes: AppRouteRecordRaw[] = [
19
+ {
20
+ path: "/notification-center",
21
+ handle: {
22
+ layout: "container",
23
+ title: "notification:menu.notificationCenter",
24
+ icon: createElement(BellOutlined),
25
+ hideInMenu: true,
26
+ },
27
+ children: [
28
+ {
29
+ index: true,
30
+ Component: NotificationCenter,
31
+ handle: {
32
+ title: "notification:menu.notificationCenter",
33
+ icon: createElement(BellOutlined),
34
+ },
35
+ },
36
+ ],
37
+ },
38
+ ];
39
+
7
40
  /**
8
- * notification 模块(G5 模板形态,对齐 apps/playground-oj/web/src/notification)。
41
+ * notification 模块(G5 模板形态):通知聚合的唯一前端消费面。
9
42
  *
10
- * 无页面路由;仅通过 onInit 全量接管通知 API(D9 + G4):把内置 root 级通知读/写
11
- * 收敛到本模块 `/notification` 前缀下的 oj 后端,通知铃的互动(单条已读/全部已读/
12
- * 清空)由此生效;发射端三方法(push/pushBroadcast/del)使本模块同时作为跨模块
13
- * 通知原语的接收端(前端 facade 委托至此)。
43
+ * onInit 全量接管通知 API(D9 + G4):把通知读/写收敛到本模块 `/notification`
44
+ * 前缀下的 oj 后端,通知铃的互动(单条已读/全部已读/清空)由此生效;发射端
45
+ * 三方法(push/pushBroadcast/del)使本模块同时作为跨模块通知原语的接收端
46
+ * (前端 facade 委托至此)。
14
47
  */
15
48
  export default defineModule({
16
49
  name: "notification",
17
- description: "通知模块(D9/G4 注入通知读写)",
18
- version: "0.0.2",
50
+ description: "通知模块(D9/G4 注入通知读写 + 通知中心页)",
51
+ version: "0.1.0",
19
52
  peerRuntime: ">=0.0.0",
20
- routes: [],
53
+ routes,
54
+ i18n: {
55
+ "zh-CN": () => import("./locales/zh-CN.json"),
56
+ "en-US": () => import("./locales/en-US.json"),
57
+ },
21
58
  lifecycle: {
22
59
  async onInit(ctx) {
23
60
  // 构造即接线:createNotificationClient 登记契约前缀 /notification
@@ -0,0 +1,19 @@
1
+ {
2
+ "menu": {
3
+ "notificationCenter": "Notifications"
4
+ },
5
+ "center": {
6
+ "tabAll": "All",
7
+ "category": {
8
+ "notice": "Notice",
9
+ "pm": "Direct",
10
+ "mention": "Mentions"
11
+ },
12
+ "markAllRead": "Mark all as read",
13
+ "clear": "Clear",
14
+ "clearConfirm": "Clear all notifications? (Broadcasts are hidden for you only)",
15
+ "empty": "No notifications",
16
+ "scopeBroadcast": "Broadcast",
17
+ "scopeUser": "Personal"
18
+ }
19
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "menu": {
3
+ "notificationCenter": "通知中心"
4
+ },
5
+ "center": {
6
+ "tabAll": "全部",
7
+ "category": {
8
+ "notice": "通知",
9
+ "pm": "私信",
10
+ "mention": "@我"
11
+ },
12
+ "markAllRead": "全部已读",
13
+ "clear": "清空",
14
+ "clearConfirm": "确定清空所有通知吗?(广播仅对您隐藏,不影响他人)",
15
+ "empty": "暂无通知",
16
+ "scopeBroadcast": "广播",
17
+ "scopeUser": "个人"
18
+ }
19
+ }