@oj-module/cli 0.2.6 → 0.2.8
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/README.md +1 -1
- package/devkit/manual.md +19 -17
- package/devkit/sql-builder-missing-capabilities-pr.md +234 -0
- package/package.json +2 -2
- package/shell-dist/assets/runtime.js +2 -2
- package/shell-dist/index.html +2 -2
- package/shell-dist/versions.json +3 -3
- package/src/contract/__tests__/handler-scan.test.ts +29 -0
- package/src/contract/__tests__/market-client.integration.test.ts +167 -0
- package/src/contract/handler-scan.ts +35 -4
- package/src/dev.ts +10 -2
- package/src/index.ts +3 -3
- package/src/init.ts +2 -0
- package/src/preview-config.ts +163 -0
- package/src/preview.ts +105 -56
- package/src/usage.ts +3 -2
- package/templates/api/config.yaml +4 -2
- package/templates/api/src/_platform/README.md +31 -0
- package/templates/api/src/_platform/_lifecycle/atomic.ts +1 -1
- package/templates/api/src/_platform/_lifecycle/history.ts +10 -5
- package/templates/api/src/_platform/_lifecycle/installer.ts +4 -4
- package/templates/api/src/_platform/_lifecycle/sha384.ts +1 -1
- package/templates/api/src/_platform/_lifecycle/steps/download.ts +1 -1
- package/templates/api/src/_platform/_lifecycle/steps/register.ts +57 -29
- package/templates/api/src/_platform/_lifecycle/trust.ts +1 -1
- package/templates/api/src/_platform/_lifecycle/uninstall.ts +13 -8
- package/templates/api/src/_platform/_lifecycle/verify-checks.ts +2 -2
- package/templates/api/src/_platform/_shared/service/{contacts.ts → domain/contacts.ts} +8 -6
- package/templates/api/src/_platform/_shared/service/{roles.ts → domain/roles.ts} +18 -19
- package/templates/api/src/_platform/_shared/service/{settings.ts → domain/settings.ts} +6 -6
- package/templates/api/src/_platform/_shared/service/{solution-perms.ts → domain/solution-perms.ts} +18 -17
- package/templates/api/src/_platform/_shared/service/{users.ts → domain/users.ts} +20 -26
- package/templates/api/src/_platform/_shared/service/{access.ts → infra/access.ts} +5 -8
- package/templates/api/src/_platform/_shared/service/{audit.ts → infra/audit.ts} +26 -26
- package/templates/api/src/_platform/_shared/service/{rate.ts → infra/rate.ts} +12 -12
- package/templates/api/src/_platform/_shared/site-facade.ts +1 -1
- package/templates/api/src/_platform/contacts/api.ts +2 -2
- package/templates/api/src/_platform/contacts/detail/api.ts +2 -2
- package/templates/api/src/_platform/manifest.yaml +3 -1
- package/templates/api/src/_platform/market/api.ts +54 -16
- package/templates/api/src/_platform/schema.yaml +14 -0
- package/templates/api/src/_platform/solutions/api.ts +13 -12
- package/templates/api/src/auth/_shared/ldap-login.ts +11 -7
- package/templates/api/src/auth/_shared/login-throttle.ts +2 -2
- package/templates/api/src/auth/_shared/session.ts +25 -21
- package/templates/api/src/auth/api.ts +1 -1
- package/templates/api/src/demo/todos/api.ts +1 -0
- package/templates/api/src/home/line/api.ts +4 -4
- package/templates/api/src/home/pie/api.ts +4 -4
- package/templates/api/src/notification/_shared/notify.ts +40 -38
- package/templates/api/src/notifications/api.ts +1 -4
- package/templates/api/src/personal-center/upload/api.ts +1 -1
- package/templates/api/src/system/login-methods/api.ts +1 -1
- package/templates/api/src/system/oplog/api.ts +3 -3
- package/templates/api/src/system/permissions/api.ts +2 -2
- package/templates/api/src/system/roles/api.ts +2 -2
- package/templates/api/src/system/roles/bindings/api.ts +2 -2
- package/templates/api/src/system/settings/api.ts +2 -2
- package/templates/api/src/system/users/api.ts +2 -2
- package/templates/api/src/system/users/forbidden/api.ts +2 -2
- package/templates/api/src/system/users/password/api.ts +2 -2
- package/templates/api/src/system/users/roles/api.ts +2 -2
- package/templates/api/src/web/user-info/api.ts +2 -5
- package/templates/api/tests/auth-session.spec.ts +1 -1
- package/templates/api/tests/auth-throttle.spec.ts +1 -1
- package/templates/api/tests/guard.spec.ts +1 -1
- package/templates/api/tests/lifecycle/market-api.spec.ts +1 -1
- package/templates/api/tests/lifecycle/trust.spec.ts +1 -1
- package/templates/api/tests/lifecycle/uninstall.spec.ts +1 -1
- package/templates/api/tests/query-utils.spec.ts +1 -1
- package/templates/api/tests/rbac-audit.spec.ts +1 -1
- package/templates/api/tests/rbac-contacts.spec.ts +2 -2
- package/templates/api/tests/rbac-guard.spec.ts +1 -1
- package/templates/api/tests/rbac-roles.spec.ts +2 -2
- package/templates/api/tests/rbac-settings.spec.ts +2 -2
- package/templates/api/tests/rbac-solution-perms.spec.ts +1 -1
- package/templates/api/tests/rbac-users.spec.ts +1 -1
- package/templates/api/tsconfig.json +8 -0
- package/templates/env.d.ts +2 -0
- package/templates/global.d.ts +816 -0
- package/templates/init.include.yaml +11 -0
- package/templates/logs/task-events.jsonl +0 -0
- package/templates/openapi.json +525 -13
- package/templates/package.json +2 -1
- package/templates/web/src/_platform/__client/api.schemas.ts +97 -0
- package/templates/web/src/_platform/__client/api.ts +152 -39
- package/templates/web/src/oj-market/__tests__/CardGrid.test.tsx +19 -0
- package/templates/web/src/oj-market/__tests__/InstallDialog.test.tsx +3 -0
- package/templates/web/src/oj-market/__tests__/RollbackDialog.test.tsx +1 -0
- package/templates/web/src/oj-market/__tests__/marketClient.fake.ts +1 -0
- package/templates/web/src/oj-market/api/client.ts +5 -105
- package/templates/web/src/oj-market/api/defaultClient.ts +111 -5
- package/templates/web/src/oj-market/components/CardGrid.tsx +4 -1
- package/templates/web/src/oj-market/components/CardItem.tsx +9 -5
- package/templates/web/src/oj-market/components/DetailDrawer.tsx +7 -3
- package/templates/web/src/oj-market/components/InstallDialog.tsx +1 -1
- package/templates/web/src/oj-market/hooks/useMarket.ts +4 -1
- package/templates/web/src/oj-market/locales/en-US.json +2 -1
- package/templates/web/src/oj-market/locales/zh-CN.json +2 -1
- package/templates/web/src/oj-market/pages/MarketApp.tsx +16 -1
- package/templates/web.config.ts +3 -3
- package/vendor/host-versions.json +3 -3
- /package/templates/api/src/_platform/_shared/service/{guard.ts → infra/guard.ts} +0 -0
- /package/templates/api/src/_platform/_shared/service/{oplog.ts → infra/oplog.ts} +0 -0
- /package/templates/api/src/_platform/_shared/service/{query.ts → infra/query.ts} +0 -0
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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<
|
|
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
|
|
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
|
|
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<
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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<
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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<
|
|
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
|
|
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) {
|
|
@@ -73,6 +73,25 @@ describe("cardGrid 卡片网格(BDD)", () => {
|
|
|
73
73
|
expect(handlers.onRollback).toHaveBeenCalledWith(installed);
|
|
74
74
|
});
|
|
75
75
|
|
|
76
|
+
it("given canManage=false(非 superadmin)When 渲染 Then 安装/启停/回滚/卸载按钮禁用、详情/历史保持可用", () => {
|
|
77
|
+
renderWithProviders(
|
|
78
|
+
<CardGrid rows={[installed]} canManage={false} {...handlers} />,
|
|
79
|
+
new InMemoryMarketClient(),
|
|
80
|
+
);
|
|
81
|
+
const btn = (name: string) => screen.getByRole("button", { name }) as HTMLButtonElement;
|
|
82
|
+
// 写操作禁用
|
|
83
|
+
expect(btn("升级").disabled).toBe(true);
|
|
84
|
+
expect(btn("停用").disabled).toBe(true);
|
|
85
|
+
expect(btn("卸载").disabled).toBe(true);
|
|
86
|
+
expect((screen.getByTestId("card-rollback-alpha") as HTMLButtonElement).disabled).toBe(true);
|
|
87
|
+
// 只读操作不受影响
|
|
88
|
+
expect(btn("详情").disabled).toBe(false);
|
|
89
|
+
expect(btn("历史").disabled).toBe(false);
|
|
90
|
+
// 禁用时不应触发写回调
|
|
91
|
+
btn("卸载").click();
|
|
92
|
+
expect(handlers.onUninstall).not.toHaveBeenCalled();
|
|
93
|
+
});
|
|
94
|
+
|
|
76
95
|
it("given 空列表 When 渲染 Then 显示空态", () => {
|
|
77
96
|
renderWithProviders(<CardGrid rows={[]} {...handlers} />, new InMemoryMarketClient());
|
|
78
97
|
expect(screen.getByTestId("card-grid-empty")).toBeTruthy();
|
|
@@ -18,6 +18,7 @@ describe("installDialog 安装进度(BDD)", () => {
|
|
|
18
18
|
progress: 100,
|
|
19
19
|
message: "ok",
|
|
20
20
|
stages: [],
|
|
21
|
+
startedAt: 0,
|
|
21
22
|
};
|
|
22
23
|
const client = new InMemoryMarketClient({ taskRecord: done, installResult: { task_id: "t1" } });
|
|
23
24
|
renderWithProviders(<InstallDialog row={row} open onClose={() => {}} />, client);
|
|
@@ -37,6 +38,7 @@ describe("installDialog 安装进度(BDD)", () => {
|
|
|
37
38
|
message: "verify failed",
|
|
38
39
|
stages: [{ stage: "verifying", ok: false, message: "bad hash" }],
|
|
39
40
|
error: { reason: "包校验失败", retryable: false, hintKey: "lifecycle.stage.verifying.hint" },
|
|
41
|
+
startedAt: 0,
|
|
40
42
|
};
|
|
41
43
|
const client = new InMemoryMarketClient({ taskRecord: failed, installResult: { task_id: "t1" } });
|
|
42
44
|
renderWithProviders(<InstallDialog row={row} open onClose={() => {}} />, client);
|
|
@@ -54,6 +56,7 @@ describe("installDialog 安装进度(BDD)", () => {
|
|
|
54
56
|
progress: 100,
|
|
55
57
|
message: "ok",
|
|
56
58
|
stages: [],
|
|
59
|
+
startedAt: 0,
|
|
57
60
|
};
|
|
58
61
|
const client = new InMemoryMarketClient({ taskRecord: done, installResult: { task_id: "t1" } });
|
|
59
62
|
const rollbackRow: IndexRow = { name: "alpha", latest: "1.2.0", installed: "1.2.0", enabled: true, upgradable: false };
|
|
@@ -4,6 +4,7 @@ import { describe, expect, it, vi } from "vitest";
|
|
|
4
4
|
import { RollbackDialog } from "../components/RollbackDialog";
|
|
5
5
|
import { InMemoryMarketClient } from "./marketClient.fake";
|
|
6
6
|
import { renderWithProviders } from "./render";
|
|
7
|
+
import "@testing-library/jest-dom/vitest";
|
|
7
8
|
|
|
8
9
|
const row: IndexRow = { name: "alpha", latest: "1.2.0", installed: "1.2.0", enabled: true, upgradable: false };
|
|
9
10
|
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
// 市场 API
|
|
2
|
-
//
|
|
1
|
+
// 市场 API 客户端契约(DIP seams):组件/hooks 依赖此接口,而非具体 http 实现;
|
|
2
|
+
// 测试可注入内存 fake(见 __tests__/marketClient.fake.ts)。
|
|
3
3
|
// 第一方专用调用面(R29):仅市场应用消费 /api/_platform/market/*,第三方方案不得仿照。
|
|
4
|
+
//
|
|
5
|
+
// 实现见同目录 defaultClient.ts——统一委托给 ojm 从契约生成的 __client,消除手写
|
|
6
|
+
// URL/信封解包与契约漂移(DEV 下生成 client 还会对响应做 zod 校验)。
|
|
4
7
|
|
|
5
8
|
import type {
|
|
6
9
|
EnableInput,
|
|
@@ -11,27 +14,6 @@ import type {
|
|
|
11
14
|
UninstallImpact,
|
|
12
15
|
} from "../types";
|
|
13
16
|
|
|
14
|
-
/** ky 形态的最小请求子集(get/post 返回带 .json<T>() 的响应) */
|
|
15
|
-
export interface HttpRequest {
|
|
16
|
-
get: <T = unknown>(
|
|
17
|
-
url: string,
|
|
18
|
-
// silentError:错误体由本客户端消化(未配置市场地址走空态),不弹全局 toast;
|
|
19
|
-
// retry: 0:503 是配置态而非抖动,默认重试 3 次只会刷出 4 条同样错误。
|
|
20
|
-
opts?: { searchParams?: Record<string, string>, silentError?: boolean, retry?: number },
|
|
21
|
-
) => Promise<{ json: <R = T>() => Promise<R> }>
|
|
22
|
-
post: <T = unknown>(
|
|
23
|
-
url: string,
|
|
24
|
-
opts?: { json?: unknown },
|
|
25
|
-
) => Promise<{ json: <R = T>() => Promise<R> }>
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/** 与运行时/生成客户端一致的响应信封(DIP:服务端统一 {code,msg,data} 包裹) */
|
|
29
|
-
interface OjEnvelope<T> {
|
|
30
|
-
code: number
|
|
31
|
-
msg?: string
|
|
32
|
-
data?: T
|
|
33
|
-
}
|
|
34
|
-
|
|
35
17
|
/** 市场客户端契约(组件/hooks 依赖此接口,而非具体 http 实现) */
|
|
36
18
|
export interface MarketClient {
|
|
37
19
|
/** 登录即可:{ apiVersion }(peerPlatform 预检口径) */
|
|
@@ -51,85 +33,3 @@ export interface MarketClient {
|
|
|
51
33
|
/** 卸载(P1-15a 补齐后接通) */
|
|
52
34
|
uninstall: (name: string) => Promise<{ ok: boolean, message: string }>
|
|
53
35
|
}
|
|
54
|
-
|
|
55
|
-
// 第一方市场端点:相对前缀,由运行时 request 的 VITE_API_BASE_URL(/api)统一加前缀;
|
|
56
|
-
// 此处若再写 /api 会与运行时前缀叠加成 /api/api/(R29 联调发现)。
|
|
57
|
-
const PLATFORM = "/_platform/market";
|
|
58
|
-
const HISTORY = "/_platform/market/history";
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* 503 = 服务端「未配置市场地址(framework.market_cdn_url)」,是**预期空态**而非故障
|
|
62
|
-
* (PRD §5.3:卡片区显示「未配置市场地址」)。模板默认不配市场地址,新工程一进市场页
|
|
63
|
-
* 就会撞它——在此归空数组,交由卡片空态文案承载;其它状态码照旧上抛。
|
|
64
|
-
*/
|
|
65
|
-
function isUnconfigured(e: unknown): boolean {
|
|
66
|
-
return (e as { response?: { status?: number } } | null)?.response?.status === 503;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/** 默认 HTTP 实现:基于运行时 request(ky 形态) */
|
|
70
|
-
export function createHttpMarketClient(request: HttpRequest): MarketClient {
|
|
71
|
-
return {
|
|
72
|
-
async meta() {
|
|
73
|
-
const r = await request.get<OjEnvelope<{ apiVersion: string }>>(`${PLATFORM}/meta`);
|
|
74
|
-
const env = await r.json();
|
|
75
|
-
return env.data!;
|
|
76
|
-
},
|
|
77
|
-
async index() {
|
|
78
|
-
try {
|
|
79
|
-
const r = await request.get<OjEnvelope<IndexRow[]>>(`${PLATFORM}/index`, {
|
|
80
|
-
silentError: true,
|
|
81
|
-
retry: 0,
|
|
82
|
-
});
|
|
83
|
-
const env = await r.json();
|
|
84
|
-
return env.data!;
|
|
85
|
-
}
|
|
86
|
-
catch (e) {
|
|
87
|
-
if (isUnconfigured(e))
|
|
88
|
-
return [];
|
|
89
|
-
throw e;
|
|
90
|
-
}
|
|
91
|
-
},
|
|
92
|
-
async install(input: InstallInput) {
|
|
93
|
-
const r = await request.post<OjEnvelope<{ task_id: string }>>(`${PLATFORM}/install`, {
|
|
94
|
-
json: {
|
|
95
|
-
name: input.name,
|
|
96
|
-
version: input.version ?? null,
|
|
97
|
-
source: input.source ?? "cdn",
|
|
98
|
-
},
|
|
99
|
-
});
|
|
100
|
-
const env = await r.json();
|
|
101
|
-
return env.data!;
|
|
102
|
-
},
|
|
103
|
-
async task(id: string) {
|
|
104
|
-
const r = await request.get<OjEnvelope<TaskRecord>>(`${PLATFORM}/task`, { searchParams: { id } });
|
|
105
|
-
const env = await r.json();
|
|
106
|
-
return env.data!;
|
|
107
|
-
},
|
|
108
|
-
async enable(input: EnableInput) {
|
|
109
|
-
const r = await request.post<OjEnvelope<{ ok: boolean, message: string }>>(`${PLATFORM}/enable`, {
|
|
110
|
-
json: { name: input.name, enabled: input.enabled },
|
|
111
|
-
});
|
|
112
|
-
const env = await r.json();
|
|
113
|
-
return env.data!;
|
|
114
|
-
},
|
|
115
|
-
async history() {
|
|
116
|
-
const r = await request.get<OjEnvelope<MarketHistory[]>>(HISTORY);
|
|
117
|
-
const env = await r.json();
|
|
118
|
-
return env.data!;
|
|
119
|
-
},
|
|
120
|
-
async uninstallImpact(name: string) {
|
|
121
|
-
const r = await request.get<OjEnvelope<UninstallImpact>>(`${PLATFORM}/uninstall-impact`, {
|
|
122
|
-
searchParams: { name },
|
|
123
|
-
});
|
|
124
|
-
const env = await r.json();
|
|
125
|
-
return env.data!;
|
|
126
|
-
},
|
|
127
|
-
async uninstall(name: string) {
|
|
128
|
-
const r = await request.post<OjEnvelope<{ ok: boolean, message: string }>>(`${PLATFORM}/uninstall`, {
|
|
129
|
-
json: { name },
|
|
130
|
-
});
|
|
131
|
-
const env = await r.json();
|
|
132
|
-
return env.data!;
|
|
133
|
-
},
|
|
134
|
-
};
|
|
135
|
-
}
|