@stalfh233/omc-cli 0.0.0-stage → 0.4.10
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/LICENSE +21 -0
- package/README.md +293 -3
- package/coverage/m1-coverage-manifest-v1.json +1278 -0
- package/dist/approval-token.js +102 -0
- package/dist/args.js +25 -0
- package/dist/artifacts.js +119 -0
- package/dist/bench/call-face-eval.js +256 -0
- package/dist/bench/context-attribution.js +151 -0
- package/dist/bench/discovery-cost-eval.js +230 -0
- package/dist/bench/driver.js +81 -0
- package/dist/bench/evals.js +236 -0
- package/dist/bench/fake-http-server.js +65 -0
- package/dist/bench/instrument.js +87 -0
- package/dist/bench/intent-face-eval.js +343 -0
- package/dist/bench/run.js +166 -0
- package/dist/bench/scenario.js +343 -0
- package/dist/bench/types.js +76 -0
- package/dist/bi-wire.js +41 -0
- package/dist/bizservice-config.js +581 -0
- package/dist/call.js +153 -0
- package/dist/capability-absences.js +23 -0
- package/dist/capability-overview.js +492 -0
- package/dist/capability-shape.js +154 -0
- package/dist/cli-contract.js +70 -0
- package/dist/cli-output.js +73 -0
- package/dist/cli.js +1418 -0
- package/dist/code-rules.js +69 -0
- package/dist/command-transport.js +155 -0
- package/dist/config-store.js +195 -0
- package/dist/context.js +21 -0
- package/dist/contract-consistency.js +66 -0
- package/dist/contract-resources.js +62 -0
- package/dist/coverage-consistency.js +62 -0
- package/dist/coverage-registry.js +76 -0
- package/dist/coverage.js +130 -0
- package/dist/data-list-filter.js +114 -0
- package/dist/discovery.js +390 -0
- package/dist/endpoints.js +154 -0
- package/dist/environment-policy.js +26 -0
- package/dist/execution-metadata.js +1092 -0
- package/dist/fake/app.js +45 -0
- package/dist/fake/b2-registration.js +594 -0
- package/dist/fake/businessrule.js +242 -0
- package/dist/fake/datarule.js +72 -0
- package/dist/fake/dictionary.js +108 -0
- package/dist/fake/environment.js +30 -0
- package/dist/fake/field.js +167 -0
- package/dist/fake/form.js +101 -0
- package/dist/fake/index.js +121 -0
- package/dist/fake/list-view.js +289 -0
- package/dist/fake/model.js +136 -0
- package/dist/fake/online-js.js +18 -0
- package/dist/fake/report.js +253 -0
- package/dist/fake/routes.js +47 -0
- package/dist/fake/rule-lifecycle.js +37 -0
- package/dist/fake/runtime-data.js +367 -0
- package/dist/fake/state.js +67 -0
- package/dist/fake/workflow.js +364 -0
- package/dist/field-change.js +200 -0
- package/dist/field-families.js +896 -0
- package/dist/form-layout.js +111 -0
- package/dist/form-support.js +821 -0
- package/dist/goal-routes.js +468 -0
- package/dist/governed-execution.js +87 -0
- package/dist/human-summary.js +212 -0
- package/dist/identity.js +62 -0
- package/dist/intent/baseline.js +57 -0
- package/dist/intent/capabilities/bizservice.js +274 -0
- package/dist/intent/capabilities/businessrule.js +493 -0
- package/dist/intent/capabilities/datarule.js +187 -0
- package/dist/intent/capabilities/field.js +545 -0
- package/dist/intent/capabilities/form.js +136 -0
- package/dist/intent/capabilities/index.js +64 -0
- package/dist/intent/capabilities/listview.js +157 -0
- package/dist/intent/capabilities/model.js +100 -0
- package/dist/intent/capabilities/onlinejs.js +108 -0
- package/dist/intent/capabilities/report.js +355 -0
- package/dist/intent/capabilities/workflow.js +458 -0
- package/dist/intent/capability.js +6 -0
- package/dist/intent/cli.js +91 -0
- package/dist/intent/compare.js +56 -0
- package/dist/intent/compiler.js +79 -0
- package/dist/intent/dsl.js +129 -0
- package/dist/intent/plan-file.js +63 -0
- package/dist/intent/readback.js +65 -0
- package/dist/intent/schema.js +158 -0
- package/dist/intent/validation.js +30 -0
- package/dist/intent/yaml.js +315 -0
- package/dist/json-column.js +68 -0
- package/dist/lanes/app-contract.js +95 -0
- package/dist/lanes/app-coverage.js +16 -0
- package/dist/lanes/app.js +174 -0
- package/dist/lanes/apply-changes.js +231 -0
- package/dist/lanes/b2-registration-contract.js +292 -0
- package/dist/lanes/b2-registration-coverage.js +48 -0
- package/dist/lanes/b2-registration.js +1187 -0
- package/dist/lanes/businessrule-contract.js +232 -0
- package/dist/lanes/businessrule-coverage.js +16 -0
- package/dist/lanes/businessrule.js +221 -0
- package/dist/lanes/contract-support.js +65 -0
- package/dist/lanes/coverage-declaration.js +9 -0
- package/dist/lanes/datarule-contract.js +155 -0
- package/dist/lanes/datarule-coverage.js +19 -0
- package/dist/lanes/datarule-protocol.js +308 -0
- package/dist/lanes/datarule.js +818 -0
- package/dist/lanes/dictionary-contract.js +78 -0
- package/dist/lanes/dictionary-coverage.js +24 -0
- package/dist/lanes/dictionary.js +235 -0
- package/dist/lanes/environment-contract.js +70 -0
- package/dist/lanes/environment-coverage.js +14 -0
- package/dist/lanes/environment.js +163 -0
- package/dist/lanes/field-contract.js +223 -0
- package/dist/lanes/field-coverage.js +27 -0
- package/dist/lanes/field.js +374 -0
- package/dist/lanes/form-contract.js +97 -0
- package/dist/lanes/form-coverage.js +16 -0
- package/dist/lanes/form.js +185 -0
- package/dist/lanes/lane-ids.js +34 -0
- package/dist/lanes/list-view-contract.js +175 -0
- package/dist/lanes/list-view-coverage.js +20 -0
- package/dist/lanes/list-view-shapes.js +1207 -0
- package/dist/lanes/list-view.js +578 -0
- package/dist/lanes/meta-contract.js +85 -0
- package/dist/lanes/meta.js +255 -0
- package/dist/lanes/model-contract.js +168 -0
- package/dist/lanes/model-coverage.js +20 -0
- package/dist/lanes/model.js +986 -0
- package/dist/lanes/online-js-contract.js +99 -0
- package/dist/lanes/online-js-coverage.js +28 -0
- package/dist/lanes/online-js.js +127 -0
- package/dist/lanes/report-contract.js +144 -0
- package/dist/lanes/report-coverage.js +21 -0
- package/dist/lanes/report.js +476 -0
- package/dist/lanes/rule-graph.js +1846 -0
- package/dist/lanes/rule-lifecycle-contract.js +92 -0
- package/dist/lanes/rule-lifecycle-coverage.js +20 -0
- package/dist/lanes/rule-lifecycle.js +176 -0
- package/dist/lanes/runtime-data-contract.js +264 -0
- package/dist/lanes/runtime-data-coverage.js +25 -0
- package/dist/lanes/runtime-data.js +1054 -0
- package/dist/lanes/workflow-contract.js +223 -0
- package/dist/lanes/workflow-coverage.js +40 -0
- package/dist/lanes/workflow.js +1813 -0
- package/dist/online-js-layout.js +58 -0
- package/dist/online-js-source.js +276 -0
- package/dist/package-tool.js +51 -0
- package/dist/package.js +73 -0
- package/dist/plan.js +73 -0
- package/dist/read.js +144 -0
- package/dist/redact.js +28 -0
- package/dist/rule-support.js +587 -0
- package/dist/runtime-support.js +134 -0
- package/dist/server.js +92 -0
- package/dist/session-manager.js +30 -0
- package/dist/session.js +149 -0
- package/dist/skills.js +112 -0
- package/dist/support.js +98 -0
- package/dist/tool-types.js +127 -0
- package/dist/tools.js +59 -0
- package/dist/usage-log.js +197 -0
- package/dist/wire.js +287 -0
- package/dist/workflow-support.js +99 -0
- package/dist/write-lease.js +26 -0
- package/dist/write-lock.js +109 -0
- package/dist/write.js +176 -0
- package/dist/zip.js +156 -0
- package/docs/tool-surface-map.md +42 -0
- package/package.json +71 -6
- package/skills/omc-acceptance-criteria.md +47 -0
- package/skills/omc-business-configuration.md +257 -0
- package/skills/omc-capabilities.md +197 -0
- package/skills/omc-capability-scouting.md +55 -0
- package/skills/omc-config-draft-review.md +171 -0
- package/skills/omc-five-piece-flow.md +35 -0
- package/skills/omc-glossary.md +86 -0
- package/skills/omc-refusals.md +110 -0
- package/skills/omc-requirement-analysis.md +161 -0
- package/skills/omc-requirement-vocabulary.md +51 -0
- package/skills/omc-start-here.md +82 -0
- package/skills/omc-tool-selection.md +119 -0
- package/skills/omc-write-hazards.md +87 -0
package/dist/fake/app.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { NOT_HANDLED } from "./state.js";
|
|
2
|
+
/** app-management lane: application package CRUD. Twin of src/lanes/app.ts. */
|
|
3
|
+
export const appRoute = (ctx, input) => {
|
|
4
|
+
const q = input.query ?? {};
|
|
5
|
+
const body = (input.body ?? {});
|
|
6
|
+
switch (input.path) {
|
|
7
|
+
case "/api/api/app/apppackage/list":
|
|
8
|
+
return ctx.options.applicationList ?? [...ctx.state.apps.values()].map((app) => ({ appCode: app.code, appName: app.name, id: app.id, groupId: app.groupId, published: app.published !== false }));
|
|
9
|
+
case "/api/api/app/apppackage/list_all_group":
|
|
10
|
+
return [...ctx.state.appGroups.values()].map((group) => ({
|
|
11
|
+
id: group.id,
|
|
12
|
+
code: group.code,
|
|
13
|
+
name: group.name,
|
|
14
|
+
children: [...ctx.state.apps.values()].filter((app) => app.groupId === group.id).map((app) => ({ id: app.id, code: app.code, name: app.name, groupId: app.groupId })),
|
|
15
|
+
}));
|
|
16
|
+
case "/api/api/app/apppackage/create": {
|
|
17
|
+
const code = String(body.code);
|
|
18
|
+
ctx.state.apps.set(code, { id: `app-${ctx.state.apps.size + 1}`, code, name: String(body.name ?? code), groupId: String(body.groupId ?? [...ctx.state.appGroups.keys()][0] ?? "group-1") });
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
case "/api/api/app/apppackage/get": {
|
|
22
|
+
const app = [...ctx.state.apps.values()].find((row) => row.code === q.appCode);
|
|
23
|
+
return app ? { id: app.id, code: app.code, name: app.name, name_i18n: JSON.stringify({ "zh-CN": app.name }), groupId: app.groupId, enabled: true } : null;
|
|
24
|
+
}
|
|
25
|
+
case "/api/api/app/apppackage/update": {
|
|
26
|
+
// AppIntegrationFacadeImpl.updateAppPackage: id-required whole-record
|
|
27
|
+
// update; explicit groupId honored; blank groupId would be forced to
|
|
28
|
+
// the "default" group; enabled !== true wipes workflow favorites.
|
|
29
|
+
const target = [...ctx.state.apps.values()].find((row) => row.id === body.id);
|
|
30
|
+
if (target) {
|
|
31
|
+
if (typeof body.groupId === "string" && body.groupId)
|
|
32
|
+
target.groupId = body.groupId;
|
|
33
|
+
if (typeof body.name === "string" && body.name)
|
|
34
|
+
target.name = body.name;
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
case "/api/api/app/apppackage/delete":
|
|
39
|
+
ctx.state.apps.delete(String(q.appCode));
|
|
40
|
+
return null;
|
|
41
|
+
default:
|
|
42
|
+
return NOT_HANDLED;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
//# sourceMappingURL=app.js.map
|
|
@@ -0,0 +1,594 @@
|
|
|
1
|
+
import { businessRefusal, NOT_HANDLED, rawResponse } from "./state.js";
|
|
2
|
+
import { decryptBizServiceMethodConfigJson } from "omc-core";
|
|
3
|
+
import { buildZip, readZipEntries, zipEntryByBasename } from "../zip.js";
|
|
4
|
+
/**
|
|
5
|
+
* B2-registration lane: business integration service registry. Twin of
|
|
6
|
+
* src/lanes/b2-registration.ts. Ticket 35 fidelity: paths match ENDPOINTS
|
|
7
|
+
* exactly (`/api/api/bizservice/service/*`, `/api/api/bizservice/method/*`),
|
|
8
|
+
* service rows carry id/code/name/adapterCode (the delete path resolves the id
|
|
9
|
+
* via get_by_code first), the method-create body keys are {serviceCode,code,
|
|
10
|
+
* name,configJson?,inputParametersJson?,outputParametersJson?} and the declared
|
|
11
|
+
* parameter face round-trips through list_by_service_code, an empty
|
|
12
|
+
* adapterCode is refused 500005 (live 2026-09-12), and a missing service
|
|
13
|
+
* answers the live 500001 envelope instead of errcode 0 + null data.
|
|
14
|
+
*
|
|
15
|
+
* Ticket 92 fidelity: the platform's method-config AES entry is simulated —
|
|
16
|
+
* BizServiceMethodController create/create_list/update decrypt configJson
|
|
17
|
+
* (AES-128-ECB, static key) and persist the PLAINTEXT; a plaintext payload
|
|
18
|
+
* silently decrypts to NULL and is stored NULL. Service configJson stays
|
|
19
|
+
* plaintext on both the write and the read face (BizServiceController).
|
|
20
|
+
*/
|
|
21
|
+
function decryptMethodConfig(configJson) {
|
|
22
|
+
if (typeof configJson !== "string" || !configJson)
|
|
23
|
+
return null;
|
|
24
|
+
try {
|
|
25
|
+
const plain = decryptBizServiceMethodConfigJson(configJson);
|
|
26
|
+
JSON.parse(plain);
|
|
27
|
+
return plain;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/** Parse a parameters column into the transient model-array readback face. */
|
|
34
|
+
function parseParamArray(json) {
|
|
35
|
+
if (!json)
|
|
36
|
+
return [];
|
|
37
|
+
try {
|
|
38
|
+
const parsed = JSON.parse(json);
|
|
39
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* BizServiceMethodModel.setXxxParameterModels fidelity: when the update body
|
|
47
|
+
* carries the transient model array, the setter re-serializes it (dropping
|
|
48
|
+
* entries without bizPropertyType/externParameterType) and overwrites the
|
|
49
|
+
* JSON column. Returns the overwritten string, or undefined when the body
|
|
50
|
+
* carries no such transient key (the plain column string then applies).
|
|
51
|
+
*/
|
|
52
|
+
function applyTransientParameterOverwrite(body, key) {
|
|
53
|
+
if (!Array.isArray(body[key]))
|
|
54
|
+
return undefined;
|
|
55
|
+
const kept = body[key].filter((entry) => entry.bizPropertyType != null || entry.externParameterType != null);
|
|
56
|
+
return JSON.stringify(kept);
|
|
57
|
+
}
|
|
58
|
+
export const b2Route = (ctx, input) => {
|
|
59
|
+
const q = input.query ?? {};
|
|
60
|
+
const body = (input.body ?? {});
|
|
61
|
+
switch (input.path) {
|
|
62
|
+
case "/api/api/bizservice/category/list":
|
|
63
|
+
// Live: the list face prepends the virtual「全部」row with an empty id.
|
|
64
|
+
return [{ id: "", name: "全部" }, ...ctx.state.categories];
|
|
65
|
+
case "/api/api/bizservice/category/create": {
|
|
66
|
+
// Live: category/create {name} (BizServiceCategoryController.java:43-176).
|
|
67
|
+
const name = String(body.name ?? "");
|
|
68
|
+
if (!name.trim())
|
|
69
|
+
return businessRefusal(500005, "分类名称不能为空");
|
|
70
|
+
if (!ctx.state.categories.some((row) => row.name === name))
|
|
71
|
+
ctx.state.categories.push({ id: `fakecat_${name}`, name });
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
case "/api/api/bizservice/category/update": {
|
|
75
|
+
// Live (BizServiceCategoryController.java:109-140 +
|
|
76
|
+
// BizServiceCategoryServiceImpl.save:54-63): a missing id answers
|
|
77
|
+
// 501052; a duplicate name answers 501004 业务服务目录名称已存在.
|
|
78
|
+
const category = ctx.state.categories.find((row) => row.id === body.id);
|
|
79
|
+
if (!category)
|
|
80
|
+
return businessRefusal(501052, "第三方数据源服务目录不存在");
|
|
81
|
+
const name = String(body.name ?? "");
|
|
82
|
+
if (!name.trim())
|
|
83
|
+
return businessRefusal(500005, "分类名称不能为空");
|
|
84
|
+
if (ctx.state.categories.some((row) => row.name === name && row.id !== category.id))
|
|
85
|
+
return businessRefusal(501004, "业务服务目录名称已存在");
|
|
86
|
+
category.name = name;
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
case "/api/api/bizservice/category/delete": {
|
|
90
|
+
// Live (BizServiceCategoryController.java:142-165 +
|
|
91
|
+
// BizServiceFacadeImpl.java:196-207): a category still holding
|
|
92
|
+
// services answers 501003 — blocked, no cascade.
|
|
93
|
+
const index = ctx.state.categories.findIndex((row) => row.id === q.id);
|
|
94
|
+
if (index === -1)
|
|
95
|
+
return businessRefusal(501052, "第三方数据源服务目录不存在");
|
|
96
|
+
const referenced = [...ctx.state.services.values()].some((service) => service.serviceCategoryId === q.id);
|
|
97
|
+
if (referenced)
|
|
98
|
+
return businessRefusal(501003, "业务服务目录下存在集成服务,不可删除!");
|
|
99
|
+
ctx.state.categories.splice(index, 1);
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
case "/api/api/bizservice/dbconnpool/list": {
|
|
103
|
+
// Ticket 104 platform fidelity: the raw list face does NOT mask the
|
|
104
|
+
// password column (BizDatabaseConnectionPoolController.list only
|
|
105
|
+
// decorates creator names) — the TOOL layer strips it from readback.
|
|
106
|
+
return [...ctx.state.dbConnPools.values()].map((pool) => ({ ...pool }));
|
|
107
|
+
}
|
|
108
|
+
case "/api/api/bizservice/dbconnpool/create": {
|
|
109
|
+
// Live fidelity (BizDatabaseConnectionPoolServiceImpl.save:103-130 +
|
|
110
|
+
// ErrorCode.java:615-621): name empty → 502004, code invalid → 502003,
|
|
111
|
+
// duplicate code → 502002; datasourceType defaults to "DATABASE".
|
|
112
|
+
const code = String(body.code ?? "");
|
|
113
|
+
const name = String(body.name ?? "");
|
|
114
|
+
if (!name.trim())
|
|
115
|
+
return businessRefusal(502004, "数据库连接池名称不能为空");
|
|
116
|
+
if (!/^[A-Za-z][A-Za-z0-9_]*$/.test(code))
|
|
117
|
+
return businessRefusal(502003, `数据库连接池编码无效:${code}`);
|
|
118
|
+
if (ctx.state.dbConnPools.has(code))
|
|
119
|
+
return businessRefusal(502002, `数据库连接池已存在:${code}`);
|
|
120
|
+
if (typeof body.jdbcUrl !== "string" || !body.jdbcUrl)
|
|
121
|
+
return businessRefusal(500005, "jdbcUrl 不能为空");
|
|
122
|
+
ctx.state.dbConnPools.set(code, {
|
|
123
|
+
id: `fakepool_${code}`,
|
|
124
|
+
code,
|
|
125
|
+
name,
|
|
126
|
+
description: typeof body.description === "string" ? body.description : undefined,
|
|
127
|
+
databaseType: String(body.databaseType ?? "MySQL"),
|
|
128
|
+
datasourceType: String(body.datasourceType ?? "DATABASE"),
|
|
129
|
+
jdbcUrl: body.jdbcUrl,
|
|
130
|
+
username: typeof body.username === "string" ? body.username : undefined,
|
|
131
|
+
password: typeof body.password === "string" ? body.password : undefined,
|
|
132
|
+
externInfo: typeof body.externInfo === "string" ? body.externInfo : undefined,
|
|
133
|
+
});
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
case "/api/api/bizservice/dbconnpool/update": {
|
|
137
|
+
// Live fidelity (BizDatabaseConnectionPoolServiceImpl.update:135-168):
|
|
138
|
+
// a FULL-ROW overwrite — only createdTime is carried from the stored
|
|
139
|
+
// row; the tool must echo untouched columns or they are wiped.
|
|
140
|
+
const pool = [...ctx.state.dbConnPools.values()].find((row) => row.id === body.id || row.code === body.code);
|
|
141
|
+
if (!pool)
|
|
142
|
+
return businessRefusal(502001, "数据库连接池不存在");
|
|
143
|
+
if (typeof body.name === "string" && !body.name.trim())
|
|
144
|
+
return businessRefusal(502004, "数据库连接池名称不能为空");
|
|
145
|
+
pool.name = typeof body.name === "string" && body.name ? body.name : pool.name;
|
|
146
|
+
pool.description = body.description !== undefined ? (typeof body.description === "string" ? body.description : undefined) : pool.description;
|
|
147
|
+
pool.databaseType = typeof body.databaseType === "string" && body.databaseType ? body.databaseType : pool.databaseType;
|
|
148
|
+
pool.datasourceType = typeof body.datasourceType === "string" && body.datasourceType ? body.datasourceType : "DATABASE";
|
|
149
|
+
pool.jdbcUrl = typeof body.jdbcUrl === "string" && body.jdbcUrl ? body.jdbcUrl : pool.jdbcUrl;
|
|
150
|
+
pool.username = body.username !== undefined ? (typeof body.username === "string" ? body.username : undefined) : pool.username;
|
|
151
|
+
pool.password = body.password !== undefined ? (typeof body.password === "string" ? body.password : undefined) : pool.password;
|
|
152
|
+
pool.externInfo = body.externInfo !== undefined ? (typeof body.externInfo === "string" ? body.externInfo : undefined) : pool.externInfo;
|
|
153
|
+
return { ...pool };
|
|
154
|
+
}
|
|
155
|
+
case "/api/api/bizservice/dbconnpool/delete": {
|
|
156
|
+
// Live fidelity (BizServiceFacadeImpl delete:173-189): a pool referenced
|
|
157
|
+
// by any service config's dbConnPoolCode answers 502006 — blocked.
|
|
158
|
+
const entry = [...ctx.state.dbConnPools.values()].find((row) => row.id === q.id || row.code === q.id);
|
|
159
|
+
if (!entry)
|
|
160
|
+
return businessRefusal(502001, "数据库连接池不存在");
|
|
161
|
+
const referenced = [...ctx.state.services.values()].some((service) => {
|
|
162
|
+
if (typeof service.configJson !== "string")
|
|
163
|
+
return false;
|
|
164
|
+
try {
|
|
165
|
+
const config = JSON.parse(service.configJson);
|
|
166
|
+
return Array.isArray(config.commonlist) && config.commonlist.some((item) => item.code === "databaseConnectionPoolCode" && item.value === entry.code);
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
if (referenced)
|
|
173
|
+
return businessRefusal(502006, `数据库连接池已经被业务服务引用:${entry.code}`);
|
|
174
|
+
ctx.state.dbConnPools.delete(entry.code);
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
case "/api/api/bizservice/service/adapter_config": {
|
|
178
|
+
// Ticket 105 platform fidelity (BizServiceController.java:329-344 +
|
|
179
|
+
// BizServiceFacadeImpl.java:322-328): a JSON STRING of the registered
|
|
180
|
+
// protocol adapters, each {code,name,config:{authList,commonList,
|
|
181
|
+
// serviceActionList,methodActionList}} (AdapterConfigParam.java:16-181).
|
|
182
|
+
// Faces mirror RestProtocolAdapterServiceImpl.java:50-90 (RESTFUL) and
|
|
183
|
+
// DataSqlProtocolAdapterServiceImpl.java:43-57 (DATA_SQL).
|
|
184
|
+
const adapterConfig = [
|
|
185
|
+
{
|
|
186
|
+
code: "RESTFUL",
|
|
187
|
+
name: "RESTful服务",
|
|
188
|
+
config: {
|
|
189
|
+
authList: [
|
|
190
|
+
{ code: "basic", name: "Basic Authentication", description: "根据username、password来进行鉴权", parameterlist: [
|
|
191
|
+
{ code: "username", name: "用户名", description: "请输入用户名", required: true },
|
|
192
|
+
{ code: "password", name: "密码", description: "请输入密码", required: true },
|
|
193
|
+
] },
|
|
194
|
+
{ code: "oauth_password", name: "OAuth2 Password", description: "根据客户端凭证,以及username、password来进行鉴权", parameterlist: [
|
|
195
|
+
{ code: "client_id", name: "客户端ID", description: "", required: true },
|
|
196
|
+
{ code: "client_secret", name: "客户端凭证", description: "", required: true },
|
|
197
|
+
{ code: "username", name: "用户名", description: "请输入用户名", required: true },
|
|
198
|
+
{ code: "password", name: "密码", description: "请输入密码", required: true },
|
|
199
|
+
{ code: "oauth_path", name: "获取token地址", description: "", required: true },
|
|
200
|
+
] },
|
|
201
|
+
{ code: "oauth_client", name: "OAuth2 Client Credentials", description: "根据客户端凭证进行鉴权", parameterlist: [
|
|
202
|
+
{ code: "client_id", name: "客户端ID", description: "", required: true },
|
|
203
|
+
{ code: "client_secret", name: "客户端凭证", description: "", required: true },
|
|
204
|
+
{ code: "oauth_path", name: "获取token地址", description: "", required: true },
|
|
205
|
+
] },
|
|
206
|
+
{ code: "customer", name: "无鉴权", description: "提供url即可", parameterlist: [] },
|
|
207
|
+
],
|
|
208
|
+
commonList: [{ code: "url", name: "地址URL", description: "HTTP请求路径", required: true }],
|
|
209
|
+
serviceActionList: [
|
|
210
|
+
{ code: "edit", name: "编辑", description: "编辑", visible: true },
|
|
211
|
+
{ code: "add", name: "新增", description: "新增", visible: true },
|
|
212
|
+
{ code: "sync", name: "同步", description: "同步", visible: false },
|
|
213
|
+
{ code: "delete", name: "删除", description: "删除", visible: true },
|
|
214
|
+
],
|
|
215
|
+
methodActionList: [
|
|
216
|
+
{ code: "edit", name: "编辑", description: "编辑", visible: true },
|
|
217
|
+
{ code: "run", name: "运行", description: "运行", visible: true },
|
|
218
|
+
{ code: "quote", name: "查看引用", description: "查看引用", visible: true },
|
|
219
|
+
{ code: "delete", name: "删除", description: "删除", visible: true },
|
|
220
|
+
],
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
code: "DATA_SQL",
|
|
225
|
+
name: "数据服务SQL",
|
|
226
|
+
config: {
|
|
227
|
+
authList: [],
|
|
228
|
+
commonList: [{ code: "databaseConnectionPoolCode", name: "数据库连接池编码", description: "数据库连接池", required: true }],
|
|
229
|
+
serviceActionList: [
|
|
230
|
+
{ code: "edit", name: "编辑", description: "编辑", visible: true },
|
|
231
|
+
{ code: "add", name: "新增", description: "新增", visible: true },
|
|
232
|
+
{ code: "sync", name: "同步", description: "同步", visible: false },
|
|
233
|
+
{ code: "delete", name: "删除", description: "删除", visible: true },
|
|
234
|
+
],
|
|
235
|
+
methodActionList: [
|
|
236
|
+
{ code: "edit", name: "编辑", description: "编辑", visible: true },
|
|
237
|
+
{ code: "run", name: "运行", description: "运行", visible: true },
|
|
238
|
+
{ code: "quote", name: "查看引用", description: "查看引用", visible: true },
|
|
239
|
+
{ code: "delete", name: "删除", description: "删除", visible: true },
|
|
240
|
+
],
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
];
|
|
244
|
+
return JSON.stringify(adapterConfig);
|
|
245
|
+
}
|
|
246
|
+
case "/api/api/bizservice/method/get_tablename_list": {
|
|
247
|
+
// Ticket 105 platform fidelity (BizServiceMethodController.java:503-537):
|
|
248
|
+
// service must exist (500001) AND be DATA_TABLE (501010
|
|
249
|
+
// 业务服务不为DataTable类型 — the research doc's "DATA_SQL discovery"
|
|
250
|
+
// reading was wrong); answers the pool's table names.
|
|
251
|
+
const service = ctx.state.services.get(q.serviceCode);
|
|
252
|
+
if (!service)
|
|
253
|
+
return businessRefusal(500001, "业务服务不存在");
|
|
254
|
+
if (service.adapterCode !== "DATA_TABLE")
|
|
255
|
+
return businessRefusal(501010, "业务服务不为DataTable类型");
|
|
256
|
+
return ["h_biz_schema", "h_biz_service"];
|
|
257
|
+
}
|
|
258
|
+
case "/api/api/bizservice/method/get_table_column": {
|
|
259
|
+
// Ticket 105 platform fidelity (BizServiceMethodController.java:538-560
|
|
260
|
+
// + BizServiceFacadeImpl.getDataTableSql:889-910): answers GENERATED SQL
|
|
261
|
+
// TEMPLATES (DataTableSqlModel{sql,sqlType}, SqlType
|
|
262
|
+
// SELECT/UPDATE/DELETE/INSERT/UPSERT) — not column metadata.
|
|
263
|
+
const service = ctx.state.services.get(q.serviceCode);
|
|
264
|
+
if (!service)
|
|
265
|
+
return businessRefusal(500001, "业务服务不存在");
|
|
266
|
+
if (service.adapterCode !== "DATA_TABLE")
|
|
267
|
+
return businessRefusal(501010, "业务服务不为DataTable类型");
|
|
268
|
+
const table = String(q.tableName ?? "");
|
|
269
|
+
return [
|
|
270
|
+
{ sql: `SELECT * FROM ${table}`, sqlType: "SELECT" },
|
|
271
|
+
{ sql: `INSERT INTO ${table} (...) VALUES (...)`, sqlType: "INSERT" },
|
|
272
|
+
{ sql: `UPDATE ${table} SET ... WHERE ...`, sqlType: "UPDATE" },
|
|
273
|
+
{ sql: `DELETE FROM ${table} WHERE ...`, sqlType: "DELETE" },
|
|
274
|
+
];
|
|
275
|
+
}
|
|
276
|
+
case "/api/api/bizservice/service/create": {
|
|
277
|
+
// Live: create with an empty adapterCode → 500005 业务服务关联适配器编码为空.
|
|
278
|
+
if (typeof body.adapterCode !== "string" || !body.adapterCode)
|
|
279
|
+
return businessRefusal(500005, "业务服务关联适配器编码为空");
|
|
280
|
+
const code = String(body.code ?? "");
|
|
281
|
+
ctx.state.services.set(code, {
|
|
282
|
+
id: `fakesvc_${code}`,
|
|
283
|
+
code,
|
|
284
|
+
serviceCode: code,
|
|
285
|
+
name: body.name,
|
|
286
|
+
adapterCode: body.adapterCode,
|
|
287
|
+
serviceCategoryId: typeof body.serviceCategoryId === "string" ? body.serviceCategoryId : undefined,
|
|
288
|
+
configJson: typeof body.configJson === "string" ? body.configJson : undefined,
|
|
289
|
+
methods: [],
|
|
290
|
+
});
|
|
291
|
+
return null;
|
|
292
|
+
}
|
|
293
|
+
case "/api/api/bizservice/service/update": {
|
|
294
|
+
// Live: update requires the row id (BizServiceController.java:103-128);
|
|
295
|
+
// the tool always resolves it via get_by_code first. Fidelity note
|
|
296
|
+
// (live incident 2026-09-14): the platform update is a FULL-ROW
|
|
297
|
+
// overwrite — body keys that are absent/typed-out null the stored
|
|
298
|
+
// column. The fake mirrors that overwrite semantics (no merge), so an
|
|
299
|
+
// update body that forgets configJson fails the readback here exactly
|
|
300
|
+
// like it would on the platform.
|
|
301
|
+
if (typeof body.id !== "string" || !body.id)
|
|
302
|
+
return businessRefusal(500001, "业务服务不存在");
|
|
303
|
+
let updated = null;
|
|
304
|
+
for (const service of ctx.state.services.values()) {
|
|
305
|
+
if (service.id === body.id) {
|
|
306
|
+
service.name = body.name;
|
|
307
|
+
service.configJson = typeof body.configJson === "string" ? body.configJson : null;
|
|
308
|
+
service.serviceCategoryId = typeof body.serviceCategoryId === "string" ? body.serviceCategoryId : undefined;
|
|
309
|
+
service.shared = body.shared === true;
|
|
310
|
+
service.userIdList = Array.isArray(body.userIdList) ? body.userIdList : [];
|
|
311
|
+
service.modifierList = Array.isArray(body.modifierList) ? body.modifierList : [];
|
|
312
|
+
updated = { id: service.id, code: service.code, name: service.name, adapterCode: service.adapterCode ?? "", ...(service.configJson !== undefined && service.configJson !== null ? { configJson: service.configJson } : {}) };
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return updated;
|
|
316
|
+
}
|
|
317
|
+
case "/api/api/bizservice/service/get_by_code": {
|
|
318
|
+
const service = ctx.state.services.get(q.serviceCode);
|
|
319
|
+
// Live: get_by_code throws PortalException 500001 业务服务不存在.
|
|
320
|
+
return service
|
|
321
|
+
? { id: service.id, code: service.code, name: service.name, adapterCode: service.adapterCode ?? "", ...(service.serviceCategoryId !== undefined ? { serviceCategoryId: service.serviceCategoryId } : {}), ...(service.configJson !== undefined ? { configJson: service.configJson } : {}) }
|
|
322
|
+
: businessRefusal(500001, "业务服务不存在");
|
|
323
|
+
}
|
|
324
|
+
case "/api/api/bizservice/method/create": {
|
|
325
|
+
const service = ctx.state.services.get(String(body.serviceCode));
|
|
326
|
+
if (service)
|
|
327
|
+
service.methods.push({
|
|
328
|
+
id: `fakemethod_${String(body.serviceCode)}_${String(body.code ?? "")}`,
|
|
329
|
+
code: String(body.code ?? ""),
|
|
330
|
+
name: body.name,
|
|
331
|
+
// Platform entry: decrypt then persist plaintext; NULL on failure.
|
|
332
|
+
configJson: decryptMethodConfig(body.configJson),
|
|
333
|
+
inputParametersJson: typeof body.inputParametersJson === "string" ? body.inputParametersJson : undefined,
|
|
334
|
+
outputParametersJson: typeof body.outputParametersJson === "string" ? body.outputParametersJson : undefined,
|
|
335
|
+
});
|
|
336
|
+
return null;
|
|
337
|
+
}
|
|
338
|
+
case "/api/api/bizservice/method/get": {
|
|
339
|
+
const method = [...ctx.state.services.values()].flatMap((service) => service.methods).find((candidate) => candidate.id === q.id);
|
|
340
|
+
return method ? { ...method, configJson: method.configJson ?? null, inputParametersJson: method.inputParametersJson ?? null, outputParametersJson: method.outputParametersJson ?? null } : businessRefusal(500001, "业务方法不存在");
|
|
341
|
+
}
|
|
342
|
+
case "/api/api/bizservice/method/update": {
|
|
343
|
+
const service = [...ctx.state.services.values()].find((candidate) => candidate.methods.some((method) => method.id === body.id));
|
|
344
|
+
const method = service?.methods.find((candidate) => candidate.id === body.id);
|
|
345
|
+
if (!method)
|
|
346
|
+
return businessRefusal(500001, "业务方法不存在");
|
|
347
|
+
method.code = String(body.code ?? method.code);
|
|
348
|
+
method.name = body.name;
|
|
349
|
+
if (body.configJson !== undefined)
|
|
350
|
+
method.configJson = decryptMethodConfig(body.configJson);
|
|
351
|
+
// Live 2026-09-15 fidelity (BizServiceMethodModel.java:88-146): the
|
|
352
|
+
// transient inputParameterModels/outputParameterModels setters
|
|
353
|
+
// RE-SERIALIZE and overwrite the JSON columns, filtering out entries
|
|
354
|
+
// without bizPropertyType/externParameterType (an untyped face becomes
|
|
355
|
+
// "[]"). The plain *ParametersJson string setters persist verbatim.
|
|
356
|
+
method.inputParametersJson = applyTransientParameterOverwrite(body, "inputParameterModels") ?? (typeof body.inputParametersJson === "string" ? body.inputParametersJson : method.inputParametersJson);
|
|
357
|
+
method.outputParametersJson = applyTransientParameterOverwrite(body, "outputParameterModels") ?? (typeof body.outputParametersJson === "string" ? body.outputParametersJson : method.outputParametersJson);
|
|
358
|
+
return null;
|
|
359
|
+
}
|
|
360
|
+
case "/api/api/bizservice/method/delete": {
|
|
361
|
+
// Live fidelity: delete keys on the row id (comma-separated on the
|
|
362
|
+
// platform face); a method still referenced by a business-rule mapping
|
|
363
|
+
// answers 500108 业务方法已绑定默认方法,不可删除.
|
|
364
|
+
let removed = false;
|
|
365
|
+
for (const targetId of String(q.id ?? "").split(",").filter(Boolean)) {
|
|
366
|
+
for (const service of ctx.state.services.values()) {
|
|
367
|
+
const method = service.methods.find((candidate) => candidate.id === targetId);
|
|
368
|
+
if (!method)
|
|
369
|
+
continue;
|
|
370
|
+
if (method.referenced)
|
|
371
|
+
return businessRefusal(500108, "业务方法已绑定默认方法,不可删除");
|
|
372
|
+
service.methods = service.methods.filter((candidate) => candidate.id !== targetId);
|
|
373
|
+
removed = true;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
if (!removed)
|
|
377
|
+
return businessRefusal(500001, "业务方法不存在");
|
|
378
|
+
return null;
|
|
379
|
+
}
|
|
380
|
+
case "/api/api/bizservice/method/list_by_service_code":
|
|
381
|
+
return (ctx.state.services.get(q.serviceCode)?.methods ?? []).map((method) => ({
|
|
382
|
+
id: method.id,
|
|
383
|
+
code: method.code,
|
|
384
|
+
name: method.name,
|
|
385
|
+
serviceCode: q.serviceCode,
|
|
386
|
+
configJson: method.configJson ?? null,
|
|
387
|
+
inputParametersJson: method.inputParametersJson ?? null,
|
|
388
|
+
outputParametersJson: method.outputParametersJson ?? null,
|
|
389
|
+
// Live readback also parses the columns into the transient model
|
|
390
|
+
// arrays (inputParameterModels/outputParameterModels on the model).
|
|
391
|
+
inputParameterModels: parseParamArray(method.inputParametersJson),
|
|
392
|
+
outputParameterModels: parseParamArray(method.outputParametersJson),
|
|
393
|
+
referenced: method.referenced === true,
|
|
394
|
+
}));
|
|
395
|
+
case "/api/api/bizservice/service/delete": {
|
|
396
|
+
for (const [code, service] of ctx.state.services) {
|
|
397
|
+
if (service.id === q.id || code === q.id)
|
|
398
|
+
ctx.state.services.delete(code);
|
|
399
|
+
}
|
|
400
|
+
return null;
|
|
401
|
+
}
|
|
402
|
+
// -----------------------------------------------------------------------
|
|
403
|
+
// Ticket 106 — the IE (import/export) face
|
|
404
|
+
// -----------------------------------------------------------------------
|
|
405
|
+
case "/api/api/runtime/query/upload_file": {
|
|
406
|
+
// QueryRuntimeController.java:2414-2428: multipart field `file`, the
|
|
407
|
+
// body answers a PLAIN STRING refId (not an envelope).
|
|
408
|
+
if (!input.multipart)
|
|
409
|
+
return businessRefusal(10005, "非法的参数");
|
|
410
|
+
ctx.state.ieUploadSeq += 1;
|
|
411
|
+
const refId = `fakeref_${ctx.state.ieUploadSeq}`;
|
|
412
|
+
ctx.state.ieUploads.set(refId, Buffer.from(input.multipart.content));
|
|
413
|
+
return rawResponse(refId);
|
|
414
|
+
}
|
|
415
|
+
case "/api/api/bizservice/service/export": {
|
|
416
|
+
// BizServiceIEController.java:110-148 + BizServiceIEFacadeImpl:135-148:
|
|
417
|
+
// the package copies the stored rows VERBATIM (service configJson
|
|
418
|
+
// plaintext incl. auth values; method configJson stored plaintext) and
|
|
419
|
+
// never touches the connection pools. Unknown codes are silently
|
|
420
|
+
// skipped (the tool preflights them away).
|
|
421
|
+
const services = [];
|
|
422
|
+
const methodsMap = {};
|
|
423
|
+
for (const code of (Array.isArray(body.serviceCodes) ? body.serviceCodes : [])) {
|
|
424
|
+
const service = ctx.state.services.get(code);
|
|
425
|
+
if (!service)
|
|
426
|
+
continue;
|
|
427
|
+
services.push({
|
|
428
|
+
code: service.code,
|
|
429
|
+
name: service.name,
|
|
430
|
+
adapterCode: service.adapterCode,
|
|
431
|
+
serviceCategoryId: service.serviceCategoryId,
|
|
432
|
+
configJson: service.configJson ?? null,
|
|
433
|
+
shared: service.shared === true,
|
|
434
|
+
userIdList: service.userIdList ?? [],
|
|
435
|
+
modifierList: service.modifierList ?? [],
|
|
436
|
+
});
|
|
437
|
+
methodsMap[code] = service.methods.map((method) => ({
|
|
438
|
+
code: method.code,
|
|
439
|
+
name: method.name,
|
|
440
|
+
serviceCode: code,
|
|
441
|
+
// Live 2026-09-15 fidelity: the serialized model carries BOTH the
|
|
442
|
+
// transient decoded `config` object and the plaintext `configJson`
|
|
443
|
+
// string column (bizService-<uuid>/manifest.json).
|
|
444
|
+
...(method.configJson ? { config: JSON.parse(method.configJson), configJson: method.configJson } : { configJson: method.configJson ?? null }),
|
|
445
|
+
inputParametersJson: method.inputParametersJson ?? null,
|
|
446
|
+
outputParametersJson: method.outputParametersJson ?? null,
|
|
447
|
+
referenced: method.referenced === true,
|
|
448
|
+
}));
|
|
449
|
+
}
|
|
450
|
+
const manifest = { systemVersion: "8.6.26", services, methodsMap };
|
|
451
|
+
// Live fidelity: the controller compresses the staging DIRECTORY, so
|
|
452
|
+
// every entry carries a bizService-<uuid>/ prefix.
|
|
453
|
+
const staging = `bizService-${String(Math.random().toFixed(32)).replaceAll(".", "")}`;
|
|
454
|
+
const zip = buildZip([
|
|
455
|
+
{ name: `${staging}/manifest.json`, data: Buffer.from(JSON.stringify(manifest), "utf8") },
|
|
456
|
+
{ name: `${staging}/version.md`, data: Buffer.from("8.6.26", "utf8") },
|
|
457
|
+
]);
|
|
458
|
+
return rawResponse(zip);
|
|
459
|
+
}
|
|
460
|
+
case "/api/api/bizservice/service/check":
|
|
461
|
+
case "/api/api/bizservice/service/import": {
|
|
462
|
+
// Both faces consume their OWN uploaded refId (one-shot:
|
|
463
|
+
// FileOperateHelper2.java:43-57 removes the cache entry on download).
|
|
464
|
+
const refId = String(body.fileName ?? "");
|
|
465
|
+
const uploaded = ctx.state.ieUploads.get(refId);
|
|
466
|
+
ctx.state.ieUploads.delete(refId);
|
|
467
|
+
if (uploaded === undefined)
|
|
468
|
+
return businessRefusal(10005, "非法的参数");
|
|
469
|
+
let manifest;
|
|
470
|
+
try {
|
|
471
|
+
const entries = readZipEntries(uploaded);
|
|
472
|
+
const manifestEntry = zipEntryByBasename(entries, "manifest.json");
|
|
473
|
+
if (manifestEntry === undefined)
|
|
474
|
+
throw new Error("no manifest");
|
|
475
|
+
manifest = JSON.parse(manifestEntry.toString("utf8"));
|
|
476
|
+
if (!Array.isArray(manifest.services) || manifest.services.length === 0)
|
|
477
|
+
throw new Error("empty services");
|
|
478
|
+
}
|
|
479
|
+
catch {
|
|
480
|
+
return businessRefusal(10005, "格式校验错误");
|
|
481
|
+
}
|
|
482
|
+
const modifyCodes = (Array.isArray(body.modifyServiceCodes) ? body.modifyServiceCodes : []);
|
|
483
|
+
const overWrite = body.overWrite === true;
|
|
484
|
+
const isCheck = input.path.endsWith("/check");
|
|
485
|
+
if (isCheck) {
|
|
486
|
+
// BizServiceIEFacadeImpl.checkBizService: flag repeated codes, fill
|
|
487
|
+
// serviceName/groupName, validate renames, report misses.
|
|
488
|
+
const reported = [...modifyCodes];
|
|
489
|
+
for (const service of manifest.services) {
|
|
490
|
+
const code = String(service.code ?? "");
|
|
491
|
+
const local = ctx.state.services.get(code);
|
|
492
|
+
if (!local)
|
|
493
|
+
continue;
|
|
494
|
+
const category = ctx.state.categories.find((row) => row.id === local.serviceCategoryId);
|
|
495
|
+
const modify = reported.find((row) => row.oldServiceCode === code);
|
|
496
|
+
if (!modify) {
|
|
497
|
+
reported.push({ serviceName: local.name, groupName: category?.name ?? "", isRepeated: true, oldServiceCode: code });
|
|
498
|
+
}
|
|
499
|
+
else {
|
|
500
|
+
modify.serviceName = local.name;
|
|
501
|
+
modify.groupName = category?.name ?? "";
|
|
502
|
+
const newCode = String(modify.newServiceCode ?? "");
|
|
503
|
+
if (!/^[a-zA-Z][a-zA-Z0-9_]{0,27}$/.test(newCode))
|
|
504
|
+
return businessRefusal(580001, `${newCode}编码命名不合法`);
|
|
505
|
+
modify.isRepeated = ctx.state.services.has(newCode);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
return { fileName: refId, modifyServiceCodes: reported, missedDataSourceCodes: [], missedUserList: [] };
|
|
509
|
+
}
|
|
510
|
+
// import (BizServiceIEFacadeImpl.importBizServices, @Transactional)
|
|
511
|
+
if (overWrite)
|
|
512
|
+
modifyCodes.length = 0;
|
|
513
|
+
for (const service of manifest.services) {
|
|
514
|
+
const packagedCode = String(service.code ?? "");
|
|
515
|
+
if (typeof body.groupId === "string" && body.groupId)
|
|
516
|
+
service.serviceCategoryId = body.groupId;
|
|
517
|
+
const local = ctx.state.services.get(packagedCode);
|
|
518
|
+
const modify = modifyCodes.find((row) => row.oldServiceCode === packagedCode);
|
|
519
|
+
if (local != null && modify == null && !overWrite)
|
|
520
|
+
return businessRefusal(309008, `${packagedCode}服务编码重复未解决`);
|
|
521
|
+
const finalCode = local != null && (overWrite || modify == null) ? packagedCode : String(modify?.newServiceCode ?? packagedCode);
|
|
522
|
+
const methods = manifest.methodsMap?.[packagedCode] ?? [];
|
|
523
|
+
if (local != null && overWrite) {
|
|
524
|
+
local.name = service.name;
|
|
525
|
+
local.adapterCode = service.adapterCode;
|
|
526
|
+
local.serviceCategoryId = service.serviceCategoryId;
|
|
527
|
+
local.configJson = service.configJson;
|
|
528
|
+
}
|
|
529
|
+
else {
|
|
530
|
+
ctx.state.services.set(finalCode, {
|
|
531
|
+
id: `fakesvc_${finalCode}`,
|
|
532
|
+
code: finalCode,
|
|
533
|
+
serviceCode: finalCode,
|
|
534
|
+
name: service.name,
|
|
535
|
+
adapterCode: service.adapterCode,
|
|
536
|
+
serviceCategoryId: service.serviceCategoryId,
|
|
537
|
+
configJson: service.configJson,
|
|
538
|
+
methods: [],
|
|
539
|
+
});
|
|
540
|
+
for (const method of methods)
|
|
541
|
+
method.serviceCode = finalCode;
|
|
542
|
+
}
|
|
543
|
+
const target = ctx.state.services.get(finalCode);
|
|
544
|
+
for (const method of methods) {
|
|
545
|
+
const existing = target.methods.find((row) => row.code === method.code);
|
|
546
|
+
const row = {
|
|
547
|
+
id: existing?.id ?? `fakemethod_${finalCode}_${method.code}`,
|
|
548
|
+
code: method.code,
|
|
549
|
+
name: method.name,
|
|
550
|
+
// The IE path persists the package verbatim — no AES anywhere.
|
|
551
|
+
configJson: method.configJson ?? null,
|
|
552
|
+
inputParametersJson: method.inputParametersJson ?? undefined,
|
|
553
|
+
outputParametersJson: method.outputParametersJson ?? undefined,
|
|
554
|
+
referenced: false,
|
|
555
|
+
};
|
|
556
|
+
if (existing)
|
|
557
|
+
Object.assign(existing, row);
|
|
558
|
+
else
|
|
559
|
+
target.methods.push(row);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
return { fileName: refId, modifyServiceCodes: [], missedDataSourceCodes: [], missedUserList: [] };
|
|
563
|
+
}
|
|
564
|
+
case "/api/api/bizservice/method/service_test": {
|
|
565
|
+
// Ticket 107 (BizServiceMethodController.java:398-412 +
|
|
566
|
+
// BizServiceFacadeImpl.java:426-464): resolve the method, dispatch to
|
|
567
|
+
// the (simulated) adapter runtime, answer the INNER result map
|
|
568
|
+
// {success,msg,data}. ZERO config writes — the route only reads the
|
|
569
|
+
// stored rows (the tool's readback proves the config survived).
|
|
570
|
+
const service = ctx.state.services.get(String(body.serviceCode ?? ""));
|
|
571
|
+
if (!service)
|
|
572
|
+
return businessRefusal(500001, "业务服务不存在");
|
|
573
|
+
const method = service.methods.find((candidate) => candidate.code === body.code);
|
|
574
|
+
if (!method)
|
|
575
|
+
return businessRefusal(500001, "业务方法不存在");
|
|
576
|
+
const args = (body.testInputParametersMap ?? {});
|
|
577
|
+
// Test affordance (dogfood round20): a method whose code ends in
|
|
578
|
+
// `_errenv` simulates a same-instance RESTFUL target that answers HTTP
|
|
579
|
+
// 200 with a CloudPivot error envelope (`{errcode:50000,...}`, e.g.
|
|
580
|
+
// "corpId can not be blank") — the platform still reports success:true.
|
|
581
|
+
if (method.code.endsWith("_errenv")) {
|
|
582
|
+
return { success: true, msg: "", data: { errcode: 50000, errmsg: "corpId can not be blank" } };
|
|
583
|
+
}
|
|
584
|
+
return {
|
|
585
|
+
success: true,
|
|
586
|
+
msg: "",
|
|
587
|
+
data: { adapterCode: service.adapterCode, methodCode: method.code, received: args },
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
default:
|
|
591
|
+
return NOT_HANDLED;
|
|
592
|
+
}
|
|
593
|
+
};
|
|
594
|
+
//# sourceMappingURL=b2-registration.js.map
|