@stalfh233/omc-cli 0.4.36 → 0.4.38
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 +2 -2
- package/dist/bench/call-face-eval.js +1 -1
- package/dist/bench/discovery-cost-eval.js +1 -1
- package/dist/bench/driver.js +1 -1
- package/dist/bench/intent-face-eval.js +1 -1
- package/dist/capability-shape.js +2 -153
- package/dist/cli.js +42 -578
- package/dist/contract-consistency.js +5 -1
- package/dist/execution-metadata.js +24 -1160
- package/dist/field-families.js +2 -22
- package/dist/intent/plan-apply.js +587 -0
- package/dist/json-column.js +2 -67
- package/dist/lanes/businessrule-contract.js +4 -3
- package/dist/lanes/list-view-shapes.js +13 -98
- package/dist/lanes/model-contract.js +2 -2
- package/dist/lanes/rule-graph.js +2 -2
- package/dist/lanes/runtime-data-contract.js +6 -83
- package/dist/recipes/b2-registration.js +87 -0
- package/dist/recipes/businessrule.js +269 -0
- package/dist/recipes/datarule.js +215 -0
- package/dist/recipes/dictionary.js +42 -0
- package/dist/recipes/field.js +230 -0
- package/dist/recipes/form.js +19 -0
- package/dist/recipes/list-view.js +31 -0
- package/dist/recipes/model.js +34 -0
- package/dist/recipes/online-js.js +32 -0
- package/dist/recipes/runtime-data.js +113 -0
- package/dist/recipes/shared.js +8 -0
- package/dist/recipes/workflow.js +119 -0
- package/dist/tool-types.js +2 -7
- package/dist/zip.js +2 -155
- package/package.json +3 -2
- package/dist/bench/fake-http-server.js +0 -65
- package/dist/fake/app.js +0 -45
- package/dist/fake/b2-registration.js +0 -620
- package/dist/fake/businessrule.js +0 -242
- package/dist/fake/datarule.js +0 -72
- package/dist/fake/dictionary.js +0 -108
- package/dist/fake/environment.js +0 -30
- package/dist/fake/field.js +0 -167
- package/dist/fake/form.js +0 -101
- package/dist/fake/index.js +0 -121
- package/dist/fake/list-view.js +0 -289
- package/dist/fake/model.js +0 -136
- package/dist/fake/online-js.js +0 -18
- package/dist/fake/report.js +0 -253
- package/dist/fake/routes.js +0 -47
- package/dist/fake/rule-lifecycle.js +0 -37
- package/dist/fake/runtime-data.js +0 -367
- package/dist/fake/state.js +0 -67
- package/dist/fake/workflow.js +0 -364
package/dist/json-column.js
CHANGED
|
@@ -1,68 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
*
|
|
3
|
-
* string (or an object)" decoding/encoding. Previously every lane carried a
|
|
4
|
-
* local copy with subtly different behaviour; the deliberate differences are
|
|
5
|
-
* now NAMED POLICIES chosen at each call site:
|
|
6
|
-
*
|
|
7
|
-
* - `JSON_COLUMN_PASSTHROUGH` — non-strings pass through untouched
|
|
8
|
-
* (undefined stays undefined); unparseable strings return verbatim.
|
|
9
|
-
* (datarule options, field.list readback)
|
|
10
|
-
* - `JSON_COLUMN_NULL_COALESCE` — non-strings null-coalesce (undefined →
|
|
11
|
-
* null); blank/unparseable strings return verbatim ("" stays "").
|
|
12
|
-
* (businessrule node/route/schedulerSetting, b2 configJson/parameter faces,
|
|
13
|
-
* rule-support parameter faces, list-view condition options)
|
|
14
|
-
* - `{ invalid: "throw" }` — a corrupt column is a hard error
|
|
15
|
-
* (field.update merge base reads the stored options strictly).
|
|
16
|
-
*
|
|
17
|
-
* Blank strings ("", " ") are not valid JSON, so they always take the
|
|
18
|
-
* `invalid` branch; at every previous site that meant passthrough.
|
|
19
|
-
*/
|
|
20
|
-
export const JSON_COLUMN_PASSTHROUGH = { nonString: "passthrough", invalid: "passthrough" };
|
|
21
|
-
export const JSON_COLUMN_NULL_COALESCE = { nonString: "null", invalid: "passthrough" };
|
|
22
|
-
export function decodeJsonColumn(value, policy) {
|
|
23
|
-
if (typeof value !== "string")
|
|
24
|
-
return policy.nonString === "null" ? value ?? null : value;
|
|
25
|
-
try {
|
|
26
|
-
return JSON.parse(value);
|
|
27
|
-
}
|
|
28
|
-
catch (error) {
|
|
29
|
-
if (policy.invalid === "throw")
|
|
30
|
-
throw error;
|
|
31
|
-
return value;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
/** Wire encode: a string is sent as-is, anything else is JSON-stringified. */
|
|
35
|
-
export function encodeJsonColumn(value) {
|
|
36
|
-
return typeof value === "string" ? value : JSON.stringify(value);
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Decode an options face that may be a JSON string or already an object into
|
|
40
|
-
* a plain record (or undefined). Policies preserve the previous per-site
|
|
41
|
-
* semantics: relation options accept strings/objects/arrays loosely; the
|
|
42
|
-
* FORMULA formulaConfig validator only accepts strings that parse to a
|
|
43
|
-
* non-array object; field.update/form-scaffold strict reads throw on corrupt
|
|
44
|
-
* strings.
|
|
45
|
-
*/
|
|
46
|
-
export function decodeJsonObjectColumn(value, policy) {
|
|
47
|
-
const asRecord = (parsed) => {
|
|
48
|
-
if (!parsed || typeof parsed !== "object")
|
|
49
|
-
return undefined;
|
|
50
|
-
if (Array.isArray(parsed))
|
|
51
|
-
return policy.array === "reject" ? undefined : parsed;
|
|
52
|
-
return parsed;
|
|
53
|
-
};
|
|
54
|
-
if (typeof value === "string") {
|
|
55
|
-
try {
|
|
56
|
-
return asRecord(JSON.parse(value));
|
|
57
|
-
}
|
|
58
|
-
catch (error) {
|
|
59
|
-
if (policy.invalid === "throw")
|
|
60
|
-
throw error;
|
|
61
|
-
return undefined;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
if (policy.object === "reject")
|
|
65
|
-
return undefined;
|
|
66
|
-
return asRecord(value);
|
|
67
|
-
}
|
|
1
|
+
// C1 拆分:json-column 已下沉 omc-core(真 lane 与 @stalfh233/omc-fake-platform 共用唯一事实源);此处 re-export 保持既有 import 路径不变。
|
|
2
|
+
export * from "omc-core/json-column";
|
|
68
3
|
//# sourceMappingURL=json-column.js.map
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
export { RULE_STATUS } from "omc-core/wire-facts";
|
|
2
|
+
import { RULE_STATUS } from "omc-core/wire-facts";
|
|
1
3
|
import { behaviorBinding, CONTRACT_FAMILY, CONTRACT_REFERENCE_VERSION, assertDescriptionCarries, assertLaneContract, describeTool, emitterBinding } from "./contract-support.js";
|
|
2
4
|
import { LANES } from "./lane-ids.js";
|
|
3
5
|
import { RULE_ACTION_TYPES, RULE_CODE_TYPES, RULE_CONDITION_TYPES, RULE_DATA_SOURCE_TYPES, RULE_NODE_TEMPLATES, RULE_NODE_TYPES, RULE_SCHEDULER_CYCLE_TYPES, RULE_SCHEDULER_END_TYPES, RULE_SCHEDULER_EXECUTE_TYPES, RULE_SCHEDULER_SETTING_TEMPLATE, RULE_SCHEDULER_TRIGGER_TIME_TYPES, RULE_VALUE_TYPES } from "./rule-graph.js";
|
|
4
6
|
/** Rule `enabled` is the runtime dispatch truth; `status` may lag (platform quirk). */
|
|
5
|
-
export const RULE_STATUS = Object.freeze({ enabled: "ENABLE", disabled: "DISABLED" });
|
|
6
7
|
/** Enum re-exports: rule-graph.ts is the single source (validator + fake + contract all import it). */
|
|
7
8
|
export { RULE_VALUE_TYPES, RULE_ACTION_TYPES, RULE_CONDITION_TYPES, RULE_NODE_TYPES, RULE_NODE_TEMPLATES };
|
|
8
9
|
/** The DISABLED dead-state body every fresh rule.save upsert writes. */
|
|
@@ -120,8 +121,8 @@ export const BUSINESSRULE_LANE_CONTRACT = Object.freeze({
|
|
|
120
121
|
bizActionPersistence: Object.freeze([behaviorBinding("test/rule-list.test.ts#DYNAMIC UPDATE uses the production source-field wire and backfills the related target row", assertBusinessRuleContract)]),
|
|
121
122
|
triggerConditions: Object.freeze([behaviorBinding("test/rule-graph-validation.test.ts#C.2: UPDATE with an empty filterCondition is flagged (warning) as a whole-table operation", assertBusinessRuleContract)]),
|
|
122
123
|
compatibilityMatrix: Object.freeze([behaviorBinding("test/ticket-05-rule-compatibility-preflight.test.ts#known-invalid CREATE plus dictionary selection is refused before rule mutation", assertBusinessRuleContract)]),
|
|
123
|
-
dynamicConditionSource: Object.freeze([emitterBinding("
|
|
124
|
-
dynamicActionSource: Object.freeze([emitterBinding("
|
|
124
|
+
dynamicConditionSource: Object.freeze([emitterBinding("omc-core/wire-facts.DYNAMIC_CONDITION_SOURCE_KEY", assertBusinessRuleContract)]),
|
|
125
|
+
dynamicActionSource: Object.freeze([emitterBinding("omc-core/wire-facts.DYNAMIC_ACTION_SOURCE_KEY", assertBusinessRuleContract)]),
|
|
125
126
|
dynamicConditionValue: Object.freeze([behaviorBinding("test/rule-graph-validation.test.ts#negative: ticket 09 lesion", assertBusinessRuleContract)]),
|
|
126
127
|
dynamicActionValue: Object.freeze([behaviorBinding("test/rule-graph-validation.test.ts#negative: ticket 09 lesion", assertBusinessRuleContract)]),
|
|
127
128
|
dynamicNameKeys: Object.freeze([behaviorBinding("test/rule-list.test.ts#DYNAMIC UPDATE uses the production source-field wire", assertBusinessRuleContract)]),
|
|
@@ -1,15 +1,20 @@
|
|
|
1
|
+
export { QUERY_ACTION_TYPE, QUERY_ACTION_RELATIVE, validateButtonActionConfig } from "omc-core/list-view-wire";
|
|
2
|
+
import { QUERY_ACTION_TYPE, QUERY_ACTION_RELATIVE, validateButtonActionConfig, wireEnum } from "omc-core/list-view-wire";
|
|
1
3
|
import { z } from "zod";
|
|
2
4
|
import { ToolRefusalError } from "../tool-types.js";
|
|
3
5
|
import { decodeJsonColumn, encodeJsonColumn, JSON_COLUMN_NULL_COALESCE } from "../json-column.js";
|
|
4
6
|
import { FIELD_PROPERTY_TYPES } from "../field-families.js";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Ticket 53 — each list-view concept (its wire enums, its input schema, its
|
|
9
|
+
* encode to the wire, its decode from readback, and its dry lint) is described
|
|
10
|
+
* ONCE here. `src/lanes/list-view.ts` consumes these descriptors to register
|
|
11
|
+
* the tools and `src/fake/list-view.ts` reuses the same enum constants, so a
|
|
12
|
+
* per-shape change is a one-file edit instead of four.
|
|
13
|
+
*
|
|
14
|
+
* Everything in this module is moved verbatim from list-view.ts; wire payloads
|
|
15
|
+
* and readback objects stay byte-identical (proven by the registry-dump hash,
|
|
16
|
+
* the existing list-view tests, and the bench +0.0 gate).
|
|
17
|
+
*/
|
|
13
18
|
/** Encode an enum name to its wire numeric index (undefined when unknown). */
|
|
14
19
|
export function encodeEnumName(descriptor, name) {
|
|
15
20
|
return typeof name === "string" ? descriptor.index[name] : undefined;
|
|
@@ -70,40 +75,6 @@ function defaultQueryFilterType(propertyType) {
|
|
|
70
75
|
export const SORT_DIRECTION = wireEnum("SortDirectionType", { ASC: 1, DESC: 2 });
|
|
71
76
|
export const DISPLAY_TYPE = wireEnum("DisplayType", { INPUT: 0, RADIO: 1, CHECKBOX: 2, SELECT: 3, RANGE: 4 });
|
|
72
77
|
export const CHOICE_TYPE = wireEnum("ChoiceType", { SELECT: 1, POPUP: 2, TREE_LEFT: 3 });
|
|
73
|
-
/**
|
|
74
|
-
* BizQueryActionModel enums. `QueryActionType` (QueryActionType.java:13-35) and
|
|
75
|
-
* `QueryActionRelativeType` (BIZSHEET 0/WORKFLOW 1) both carry
|
|
76
|
-
* `@JsonValue getIndex()` so the wire body is numeric; the tool speaks the enum
|
|
77
|
-
* name and decodes on readback. `associationType`/`associationCode` are the
|
|
78
|
-
* JSON names of the DTO fields `queryActionRelativeType`/`relativeCode`
|
|
79
|
-
* (`@JsonProperty`, BizQueryActionModel.java:31-35).
|
|
80
|
-
*/
|
|
81
|
-
export const QUERY_ACTION_TYPE = wireEnum("QueryActionType", {
|
|
82
|
-
QUERY: 1,
|
|
83
|
-
ADD: 2,
|
|
84
|
-
EDIT: 3,
|
|
85
|
-
DELETE: 4,
|
|
86
|
-
IMPORT: 5,
|
|
87
|
-
EXPORT: 6,
|
|
88
|
-
CUSTOM: 7,
|
|
89
|
-
QR_CODE: 8,
|
|
90
|
-
EDITOWNER: 9,
|
|
91
|
-
BATCH_PRINT: 10,
|
|
92
|
-
BATCH_UPDATE: 11,
|
|
93
|
-
CUSTOMIZE_BTN: 12,
|
|
94
|
-
PRINT: 13,
|
|
95
|
-
COPY: 14,
|
|
96
|
-
TEMPORARY: 15,
|
|
97
|
-
SUBMIT: 16,
|
|
98
|
-
CLEAR_ROW: 17,
|
|
99
|
-
ADD_BEFORE: 18,
|
|
100
|
-
ADD_AFTER: 19,
|
|
101
|
-
MANUAL_SYNC: 20,
|
|
102
|
-
IMPORT_ATTACHMENT: 21,
|
|
103
|
-
EXPORT_ATTACHMENT: 22,
|
|
104
|
-
BATCH_SUBMIT: 23,
|
|
105
|
-
});
|
|
106
|
-
export const QUERY_ACTION_RELATIVE = wireEnum("QueryActionRelativeType", { BIZSHEET: 0, WORKFLOW: 1 });
|
|
107
78
|
/**
|
|
108
79
|
* `BizButtonModel` enums (listview custom buttons). Unlike the query DTOs
|
|
109
80
|
* above, these implement `IStringEnum` with no `@JsonValue`, so Hutool parses
|
|
@@ -391,62 +362,6 @@ export function validatePresentationRenderShape(presentation) {
|
|
|
391
362
|
presentationShape(presentation[key], key);
|
|
392
363
|
}
|
|
393
364
|
}
|
|
394
|
-
function decodeButtonActionConfig(value, code) {
|
|
395
|
-
if (value === undefined)
|
|
396
|
-
return undefined;
|
|
397
|
-
if (typeof value === "string") {
|
|
398
|
-
try {
|
|
399
|
-
value = JSON.parse(value);
|
|
400
|
-
}
|
|
401
|
-
catch (error) {
|
|
402
|
-
throw new ToolRefusalError({ status: "refused", blocker: "listview-buttons-invalid", message: `buttons ${code}: actionConfig must be valid JSON (${error.message})` });
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
406
|
-
throw new ToolRefusalError({ status: "refused", blocker: "listview-buttons-invalid", message: `buttons ${code}: actionConfig must decode to an object` });
|
|
407
|
-
}
|
|
408
|
-
return value;
|
|
409
|
-
}
|
|
410
|
-
function requireButtonConfig(config, code, bindAction) {
|
|
411
|
-
const required = bindAction === "SCRIPT" ? ["scriptData"] : bindAction === "BUSINESS_RULE" || bindAction === "FLOW" ? ["targetCode"] : bindAction === "ADD_DATA" || bindAction === "FORM" ? ["schemaCodeVal", "formListData", "configureList"] : [];
|
|
412
|
-
for (const key of required) {
|
|
413
|
-
if (config?.[key] === undefined || config[key] === null) {
|
|
414
|
-
throw new ToolRefusalError({ status: "refused", blocker: "listview-buttons-invalid", message: `buttons ${code}: ${bindAction} actionConfig requires ${key}` });
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
if (bindAction === "SCRIPT" && typeof config?.scriptData !== "string") {
|
|
418
|
-
throw new ToolRefusalError({ status: "refused", blocker: "listview-buttons-invalid", message: `buttons ${code}: SCRIPT actionConfig.scriptData must be a string` });
|
|
419
|
-
}
|
|
420
|
-
if ((bindAction === "ADD_DATA" || bindAction === "FORM") && (typeof config?.schemaCodeVal !== "object" || config.schemaCodeVal === null || Array.isArray(config.schemaCodeVal) || !Array.isArray(config.formListData) || !Array.isArray(config.configureList))) {
|
|
421
|
-
throw new ToolRefusalError({ status: "refused", blocker: "listview-buttons-invalid", message: `buttons ${code}: ${bindAction} actionConfig requires object schemaCodeVal and array formListData/configureList` });
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
export function validateButtonActionConfig(entry) {
|
|
425
|
-
const bindAction = typeof entry.bindAction === "string" ? entry.bindAction : "";
|
|
426
|
-
const code = String(entry.code ?? "");
|
|
427
|
-
const config = decodeButtonActionConfig(entry.actionConfig, code);
|
|
428
|
-
if (bindAction === "BUSINESS_RULE") {
|
|
429
|
-
if (typeof entry.targetCode !== "string" || entry.targetCode.length === 0) {
|
|
430
|
-
throw new ToolRefusalError({ status: "refused", blocker: "listview-buttons-invalid", message: `buttons ${code}: BUSINESS_RULE requires targetCode` });
|
|
431
|
-
}
|
|
432
|
-
return;
|
|
433
|
-
}
|
|
434
|
-
if (bindAction === "FLOW") {
|
|
435
|
-
if (typeof entry.targetCode !== "string" || entry.targetCode.length === 0) {
|
|
436
|
-
throw new ToolRefusalError({ status: "refused", blocker: "listview-buttons-invalid", message: `buttons ${code}: FLOW requires targetCode (workflow code)` });
|
|
437
|
-
}
|
|
438
|
-
// A caller-supplied FLOW actionConfig must carry WorkflowListData; the
|
|
439
|
-
// runtime indexes [0].workflowCode and iterates configureList. Omitted is
|
|
440
|
-
// fine — expandButtonActionConfigs derives both from targetCode.
|
|
441
|
-
if (config !== undefined && (typeof config !== "object" || config === null || !Array.isArray(config.WorkflowListData))) {
|
|
442
|
-
throw new ToolRefusalError({ status: "refused", blocker: "listview-buttons-invalid", message: `buttons ${code}: FLOW actionConfig requires a WorkflowListData array (or omit actionConfig and the tool derives it from targetCode)` });
|
|
443
|
-
}
|
|
444
|
-
return;
|
|
445
|
-
}
|
|
446
|
-
if ((bindAction === "ADD_DATA" || bindAction === "FORM") && (entry.targetModel !== undefined || entry.targetForm !== undefined || entry.configureList !== undefined) && entry.actionConfig === undefined)
|
|
447
|
-
return;
|
|
448
|
-
requireButtonConfig(config, code, bindAction);
|
|
449
|
-
}
|
|
450
365
|
export function columnsRenderCompat(columns) {
|
|
451
366
|
const violations = [];
|
|
452
367
|
for (const [index, column] of columns.entries()) {
|
|
@@ -26,7 +26,7 @@ export const MODEL_WIRE = Object.freeze({
|
|
|
26
26
|
* bypasses the tool precheck; 50000 stands for the generic ServiceException
|
|
27
27
|
* envelope family and the authoritative signal is the verbatim errmsg text.
|
|
28
28
|
*/
|
|
29
|
-
export
|
|
29
|
+
export { MODEL_REFERENCED_DELETE_ERRCODE } from "omc-core/wire-facts";
|
|
30
30
|
/**
|
|
31
31
|
* The platform create-body defaults the emitter sends verbatim. The emitter
|
|
32
32
|
* imports THIS constant to build the wire body (model.create and the
|
|
@@ -86,7 +86,7 @@ export const MODEL_LANE_CONTRACT = Object.freeze({
|
|
|
86
86
|
deleteIdNamespace: Object.freeze([behaviorBinding("test/model-delete-cross-app.test.ts#model.delete refuses fail-closed when the record exists", assertModelContract)]),
|
|
87
87
|
deleteTolerance: Object.freeze([behaviorBinding("test/model-delete-many.test.ts#model.deleteMany short-circuits already-absent codes", assertModelContract)]),
|
|
88
88
|
referencePrecheck: Object.freeze([
|
|
89
|
-
emitterBinding("
|
|
89
|
+
emitterBinding("omc-core/wire-facts.MODEL_REFERENCED_DELETE_ERRCODE", assertModelContract),
|
|
90
90
|
behaviorBinding("test/model-delete-reference-block.test.ts#model.delete refuses with model-referenced-by", assertModelContract),
|
|
91
91
|
]),
|
|
92
92
|
dependencyInvertedDelete: Object.freeze([behaviorBinding("test/model-delete-reference-block.test.ts#dependency-inverted cleanup chain passes", assertModelContract)]),
|
package/dist/lanes/rule-graph.js
CHANGED
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
* node, the key, and what is missing. It runs client-side before any wire
|
|
10
10
|
* call (dry lint) so a mis-shaped graph cannot reach the platform.
|
|
11
11
|
*/
|
|
12
|
+
export { DYNAMIC_CONDITION_SOURCE_KEY, DYNAMIC_ACTION_SOURCE_KEY } from "omc-core/wire-facts";
|
|
13
|
+
import { DYNAMIC_CONDITION_SOURCE_KEY, DYNAMIC_ACTION_SOURCE_KEY } from "omc-core/wire-facts";
|
|
12
14
|
import { decodeJsonColumn, JSON_COLUMN_NULL_COALESCE } from "../json-column.js";
|
|
13
15
|
export const RULE_VALUE_TYPES = ["DYNAMIC", "FIXED", "EMPTY", "VARIABLE", "EXPRESSION", "SYSTEM", "AGGREGATION"];
|
|
14
16
|
/**
|
|
@@ -107,8 +109,6 @@ export const RULE_NODES_NEEDING_INPUT_PARAM = Object.freeze([
|
|
|
107
109
|
"MESSAGE",
|
|
108
110
|
"QUERY",
|
|
109
111
|
]);
|
|
110
|
-
export const DYNAMIC_CONDITION_SOURCE_KEY = "currentSchemaDataItem";
|
|
111
|
-
export const DYNAMIC_ACTION_SOURCE_KEY = "currentDataItemValue";
|
|
112
112
|
/**
|
|
113
113
|
* BRANCH `exitConditionGroups` deserialize into `DataFilterCondition`, whose
|
|
114
114
|
* operator property is `ruleDataConditionType` and whose left/source property
|
|
@@ -1,85 +1,8 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { assertDescriptionCarries, assertLaneContract, behaviorBinding, CONTRACT_FAMILY, CONTRACT_REFERENCE_VERSION, describeTool, emitterBinding } from "./contract-support.js";
|
|
3
3
|
import { LANES } from "./lane-ids.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
* gate, the three-layer queryCondition, and the propertyType injection are the
|
|
7
|
-
* single source for the handler, the arg schemas, and the fake.
|
|
8
|
-
*/
|
|
9
|
-
export const RUNTIME_DATA_WIRE = Object.freeze({
|
|
10
|
-
queryConditionShape: "List<List<List<FilterModel>>>(level 1 AND across groups, level 2 OR across and-groups, level 3 AND across leaves)",
|
|
11
|
-
dslShape: "or>and>叶子",
|
|
12
|
-
queryBodyCanon: "filters:[], queryVersion:1, queryCode=schemaCode, showTotal",
|
|
13
|
-
typeCastErrcode: 10009,
|
|
14
|
-
emptyModelErrcode: 301005,
|
|
15
|
-
absenceErrcode: 304001,
|
|
16
|
-
formTypeNoWorkflow: "2",
|
|
17
|
-
formTypeWorkflow: "1",
|
|
18
|
-
replayTokenEndpoint: "/api/api/runtime/form/getReplayToken",
|
|
19
|
-
replayTokenErrcode: 100005,
|
|
20
|
-
approvalNpeErrcode: 50000,
|
|
21
|
-
workflowStartDuplicateErrcode: 40000,
|
|
22
|
-
submitChain: "submit 自持久化(ticket 18 源码证据):form/submit 持久化 bizObject.data——formType=2 submitBizSheet→saveBizObject(置 COMPLETED,mergeObject 合并);formType=1 workItem→SubmitDataChangeHandlerImpl.updateBizObject;payload {id,schemaCode,sheetCode,ownerId?,data}+actionCode:\"submit\",owner 服务端以库内行回填,data 剥 engine 键(sequenceStatus/sequenceNo)",
|
|
23
|
-
submitInPlace: "无流程且 bizObjectId 有值时先 form/load 预检(缺席 304001 拒绝),再以预检行+formData 合成最小对象直提 runtime/form/submit(submit 自持久化,无预 save/构建 load);submit 返回 objectId 必须仍是目标 id,否则拒绝;仅无 workflowCode/workItemId/workflowInstanceId 的无 id 便捷链先 form/save 建稿再直提(新建记录);带 workItemId 或 workflowInstanceId 而缺 bizObjectId 时 fail-closed 拒绝(submit-biz-object-id-required);workflowCode + 既有无实例 bizObjectId 在 8.6.26 无 REST 就地面(见 workflowStartCreateOnly),持续拒绝并指向 workflowDraftSave 两段式",
|
|
24
|
-
workflowDraftSave: "门户暂存形状(ticket 13):POST runtime/form/save 顶层带 workflowCode(无 workflowInstanceId/workItemId)→ FormRuntimeController.saveWorkflow→startWorkflow(finishStart=FALSE):同 id 建 DRAFT 行 + DRAFT 流程实例 + 发起 workItem,FormSaveVO 返回 {objectId,workflowInstanceId,workItem:{id}};必须先 GET getReplayToken(isStartWf 分支 verifyReplay,否则 100005),且 data 显式 sequenceStatus:\"DRAFT\"(createAndGetBizObject 空缺省按 PROCESSING 建实例);提交该草稿 = form/submit formType=1 + workItemId + workflowInstanceId + bizObject.id(submitWorkflowByInstanceIdAndItemId),同 id 就地 PROCESSING,绝不走 workflowCode 分支",
|
|
25
|
-
workflowStartCreateOnly: "form/submit formType=1 + workflowCode(无 workItemId)→ submitWorkflowByWorkflowCode→startWorkflowInstance(create)→BizObjectFacadeImpl.createAndGetBizObject 纯 INSERT(BizObjectInsertModel 无存在性检查)→ 既有 id 必 40000 Duplicate entry(TID 771f64ee 全栈:ExecutorBase INSERT→BizObjectServiceImplCompanion:275→40000);8.6.26 唯一 load+update 型就地发起是 WorkflowInstanceFacade 5 参重载(908 行,facade 层供二开扩展消费),无 REST 面",
|
|
26
|
-
sheetResolution: "explicit caller arg > default-form sheetCode from bizsheet/get > schemaCode fallback",
|
|
27
|
-
updateBranch: "POST runtime/form/save 更新既有记录:目标 id 必须放进 bizObject.data[\"id\"](平台 BizObjectModel.getId() 读 data 的 id 键;顶层 bizObject.id 会被忽略并退化为新建);命中既有记录时 FormRuntimeController.saveBizSheet→BizObjectFacadeImpl.updateBizObject,未命中则 createBizObject 插入",
|
|
28
|
-
updateStatusRule: "既有记录的 DRAFT/COMPLETED 状态在未显式传 sequenceStatus 时原样保留(saveBizSheet 分支),COMPLETED 记录可直接 update,无需流程",
|
|
29
|
-
updateMergeRule: "updateBizObject.mergeObject 以库内旧值打底、以本次 data 覆盖 → 部分字段(patch)更新,未传字段保持不变",
|
|
30
|
-
childRowStatusNote: "子表行(CHILD_TABLE(8))在 form-save 路径按每行 `rowStatus` 分派(BizObjectUpdateModel.convertBizObjectOpItem):Added=插入 / Modified=更新 / Deleted=删除;**缺失或其它值=immutable(静默忽略)**。门户前端会为改动行标 `rowStatus:\"Modified\"`;手拼载荷漏了它,子表改动不落库、但写仍返回 errcode 0(真机 2026-10-08:data.update 改子表行无 rowStatus,process_name/计划时间读回全不变)。OMC 自动补:带自身 id 的行→\"Modified\",无 id 的行→\"Added\",显式 rowStatus 原样保留。",
|
|
31
|
-
updateAbsentGuard: "平台对\"带 id 但库内不存在\"不报错而是静默插入(createBizObject),故 data.update 先 form/load 预检,命中缺席则以 304001 拒绝,绝不静默转新增",
|
|
32
|
-
projectionHint: "所选列在默认视图未配置(值可能存在但列表投影为 null);先用 listview.configure 配置列,或用 data.load 读单条权威值",
|
|
33
|
-
formulaFieldNote: "计算字段(FORMULA / 表单「计算」控件、子表计算规则)**不在服务端 API 路径回填/重算**:门户是**前端**算好再提交,API save/update/submit 都不会替它算(真机 2026-09-25:子表计算规则字段落库仍 null;纯主表表达式会算)。OMC 的定位是「字段配好即默认它在前台会算」——**写测试数据时应在 formData 里显式带上预算好的计算值**(让数据与预期自洽),**不要指望平台在 API 保存时替它算,也不要用 API 回读值去断言公式/计算是否正确**。**这类纯前台行为最终由人工在前台(配表单→填表)确认。** 另:带**子表计算字段**的模型,API data.save/data.update 可能因服务端重算(CalculateHandler→FormulaProcessor)NPE 而 50000(真机 2026-10-07,前台路径正常)——此类模型请改用门户录入或避开该字段,别据此判定配置错误。",
|
|
34
|
-
});
|
|
35
|
-
function encodeScalar(value) {
|
|
36
|
-
if (value === null || value === undefined)
|
|
37
|
-
return "";
|
|
38
|
-
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean")
|
|
39
|
-
return String(value);
|
|
40
|
-
if (value instanceof Date)
|
|
41
|
-
return value.toISOString();
|
|
42
|
-
return JSON.stringify(value);
|
|
43
|
-
}
|
|
44
|
-
function encodeList(value) {
|
|
45
|
-
if (Array.isArray(value))
|
|
46
|
-
return value.map(encodeScalar).join(";");
|
|
47
|
-
if (typeof value === "string")
|
|
48
|
-
return value;
|
|
49
|
-
return encodeScalar(value);
|
|
50
|
-
}
|
|
51
|
-
const numeric = (value) => Number(value);
|
|
52
|
-
function betweenBounds(expected) {
|
|
53
|
-
const [low, high] = expected.split(";").map(Number);
|
|
54
|
-
return [low ?? 0, high ?? 0];
|
|
55
|
-
}
|
|
56
|
-
export const RUNTIME_QUERY_OPERATORS = Object.freeze({
|
|
57
|
-
Eq: { encode: encodeScalar, matches: (actual, expected) => String(actual ?? "") === expected },
|
|
58
|
-
NotEq: { encode: encodeScalar, matches: (actual, expected) => String(actual ?? "") !== expected },
|
|
59
|
-
Gt: { encode: encodeScalar, matches: (actual, expected) => numeric(actual) > numeric(expected) },
|
|
60
|
-
Lt: { encode: encodeScalar, matches: (actual, expected) => numeric(actual) < numeric(expected) },
|
|
61
|
-
Gte: { encode: encodeScalar, matches: (actual, expected) => numeric(actual) >= numeric(expected) },
|
|
62
|
-
Lte: { encode: encodeScalar, matches: (actual, expected) => numeric(actual) <= numeric(expected) },
|
|
63
|
-
Like: { encode: encodeScalar, matches: (actual, expected) => String(actual ?? "").includes(expected) },
|
|
64
|
-
NotLike: { encode: encodeScalar, matches: (actual, expected) => !String(actual ?? "").includes(expected) },
|
|
65
|
-
In: { encode: encodeList, matches: (actual, expected) => expected.split(";").includes(String(actual ?? "")) },
|
|
66
|
-
NotIn: { encode: encodeList, matches: (actual, expected) => !expected.split(";").includes(String(actual ?? "")) },
|
|
67
|
-
Between: { encode: encodeList, matches: (actual, expected) => { const [low, high] = betweenBounds(expected); return numeric(actual) >= low && numeric(actual) <= high; } },
|
|
68
|
-
NotBetween: { encode: encodeList, matches: (actual, expected) => { const [low, high] = betweenBounds(expected); return !(numeric(actual) >= low && numeric(actual) <= high); } },
|
|
69
|
-
IsNull: { encode: () => "", matches: (actual) => actual === null || actual === undefined },
|
|
70
|
-
IsNotNull: { encode: () => "", matches: (actual) => actual !== null && actual !== undefined },
|
|
71
|
-
});
|
|
72
|
-
export const ENGINE_OWNED_KEYS = Object.freeze(["sequenceStatus", "2147483647_sequenceNo"]);
|
|
73
|
-
export const SUBMIT_STATUS_TRANSITIONS = Object.freeze({
|
|
74
|
-
/** Start submit / start-item finish moves the row DRAFT -> PROCESSING. */
|
|
75
|
-
workflowStart: "PROCESSING",
|
|
76
|
-
/** Approval submit with agree!==false completes the row. */
|
|
77
|
-
approvalAgree: "COMPLETED",
|
|
78
|
-
/** Approval submit with agree===false cancels the row. */
|
|
79
|
-
approvalReject: "CANCELED",
|
|
80
|
-
/** formType=2 submitBizSheet -> saveBizObject completes in place. */
|
|
81
|
-
inPlaceSubmit: "COMPLETED",
|
|
82
|
-
});
|
|
4
|
+
export { RUNTIME_DATA_WIRE, RUNTIME_QUERY_OPERATORS, ENGINE_OWNED_KEYS, SUBMIT_STATUS_TRANSITIONS } from "omc-core/wire-facts";
|
|
5
|
+
import { RUNTIME_DATA_WIRE } from "omc-core/wire-facts";
|
|
83
6
|
export function dataListDescription() {
|
|
84
7
|
const wire = RUNTIME_DATA_WIRE;
|
|
85
8
|
return `按简化过滤 DSL 查询业务对象(runtime/query/list);DSL 在 CLI 内翻译为平台 queryCondition(${wire.dslShape}),并按发布字段元数据为每个条件注入 propertyType(未知过滤字段将被拒绝,可用 rawCondition 逃生);响应仅返回选定 fields 与分页元数据;空模型返回空列表;未配列的自定义字段投影为 null——这是显示面缺列配置、不是数据缺失(data.load 有值),显式选列在结果中全为 null 而发布字段元数据显示其存在时,readback 追加 projectionHint(先用 listview.configure 配置该模型的默认视图列,或用 data.load 读单条权威值)。`;
|
|
@@ -167,10 +90,10 @@ export const RUNTIME_DATA_LANE_CONTRACT = Object.freeze({
|
|
|
167
90
|
dslShape: Object.freeze([emitterBinding("data-list-filter.SIMPLE_OP_MAP", assertRuntimeDataContract)]),
|
|
168
91
|
queryBodyCanon: Object.freeze([behaviorBinding("test/data-list.test.ts#data.list translates simplified filters", assertRuntimeDataContract)]),
|
|
169
92
|
typeCastErrcode: Object.freeze([emitterBinding("data-list-filter.injectPropertyTypes", assertRuntimeDataContract)]),
|
|
170
|
-
emptyModelErrcode: Object.freeze([emitterBinding("
|
|
171
|
-
absenceErrcode: Object.freeze([emitterBinding("
|
|
172
|
-
replayTokenErrcode: Object.freeze([emitterBinding("
|
|
173
|
-
approvalNpeErrcode: Object.freeze([emitterBinding("
|
|
93
|
+
emptyModelErrcode: Object.freeze([emitterBinding("omc-core/wire-facts.RUNTIME_DATA_WIRE", assertRuntimeDataContract)]),
|
|
94
|
+
absenceErrcode: Object.freeze([emitterBinding("omc-core/wire-facts.RUNTIME_DATA_WIRE", assertRuntimeDataContract)]),
|
|
95
|
+
replayTokenErrcode: Object.freeze([emitterBinding("omc-core/wire-facts.RUNTIME_DATA_WIRE", assertRuntimeDataContract)]),
|
|
96
|
+
approvalNpeErrcode: Object.freeze([emitterBinding("omc-core/wire-facts.RUNTIME_DATA_WIRE", assertRuntimeDataContract)]),
|
|
174
97
|
submitChain: Object.freeze([behaviorBinding("test/issue-13-data-submit.test.ts#data.submit with formType=2 issues a WorkItemSubmitVO", assertRuntimeDataContract)]),
|
|
175
98
|
submitInPlace: Object.freeze([behaviorBinding("test/issue-13-data-submit.test.ts#data.submit with bizObjectId submits an existing no-workflow record in place", assertRuntimeDataContract)]),
|
|
176
99
|
workflowDraftSave: Object.freeze([behaviorBinding("test/issue-13-data-submit.test.ts#data.save with workflowCode creates a DRAFT row", assertRuntimeDataContract)]),
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { environment, commonRecovery } from "./shared.js";
|
|
2
|
+
const restfulQueryService = Object.freeze({
|
|
3
|
+
id: "restful-query-service",
|
|
4
|
+
title: "注册 RESTFUL 查询服务 + 一个方法(含参数面)",
|
|
5
|
+
status: "requires-prior-readback",
|
|
6
|
+
tool: "service.register",
|
|
7
|
+
args: {
|
|
8
|
+
environment,
|
|
9
|
+
serviceCode: "<service_code>",
|
|
10
|
+
name: "供应商查询服务",
|
|
11
|
+
adapterCode: "RESTFUL",
|
|
12
|
+
serviceCategoryId: "<category.id>",
|
|
13
|
+
serviceConfig: {
|
|
14
|
+
auth: { code: "customer", parameterlist: [] },
|
|
15
|
+
commonlist: [{ code: "url", value: "http://<host>/api" }],
|
|
16
|
+
},
|
|
17
|
+
methodName: "querySupplier",
|
|
18
|
+
methodConfig: { httpType: "Post", requestBodyType: "JSON", url: "/supplier/query", frontEndExtensionEnable: true },
|
|
19
|
+
methodInputParameters: [{ code: "keyword", name: "关键字", required: true, configJson: { position: "REQUEST_BODY" } }],
|
|
20
|
+
methodOutputParameters: [{ code: "name", name: "供应商名称", configJson: { position: "REQUEST_BODY" } }],
|
|
21
|
+
},
|
|
22
|
+
preconditions: ["serviceCategoryId 由 service.category.list 解析(「全部」是空 id 虚拟项不可用);RESTFUL 服务 configJson 需要 auth 与 commonlist[url];带 methodName 时必须有 methodConfig"],
|
|
23
|
+
conditionalRequirements: [
|
|
24
|
+
"RESTFUL auth.code ∈ customer(parameterlist=[]) / basic(client… username/password) / oauth_password / oauth_client;parameterlist 每项 {code,value} 且必须与 auth.code 期望参数完全一致",
|
|
25
|
+
"RESTFUL 方法 configJson 必需键:httpType(Post/Get/Put/Patch/Delete)、requestBodyType(Form-urlencoded/JSON/Text)、url、frontEndExtensionEnable(布尔)",
|
|
26
|
+
"RESTFUL 每个输入/输出参数必须带 configJson.position ∈ QUERY_PARAMS/REQUEST_HEADER/REQUEST_BODY/PATH_PARAMS(URL_VARIABLE 被运行时拒 501007)",
|
|
27
|
+
"一次写只建一个方法;给既有服务加方法走 method.create(escape hatch)",
|
|
28
|
+
],
|
|
29
|
+
priorToolReferences: [
|
|
30
|
+
{ tool: "service.category.list", args: { environment }, purpose: "取服务分类 id(所属目录必填)" },
|
|
31
|
+
{ tool: "service.adapter_config", args: { environment }, purpose: "确认 RESTFUL 适配器的 commonList/authList 必需键与当前实例一致" },
|
|
32
|
+
],
|
|
33
|
+
dryRun: { supported: true, command: `omc call service.register --env ${environment} --dry-run --args '<recipe.args>'`, notes: "dry-run 做 adapter/serviceConfig/methodConfig/参数面本地预检,零 wire;用它一次性看清缺哪个键" },
|
|
34
|
+
expectedReadback: { performed: { errcode: 0 }, readback: { servicePresent: true, methodPresent: true, methodCount: 1 }, next: ["service.get 复核(凭据已脱敏)"] },
|
|
35
|
+
refusalRecovery: [
|
|
36
|
+
{ code: "bizservice-service-config-invalid", action: "serviceConfig 需要 auth{code,parameterlist[]}+commonlist[{code:'url',value}];按消息补键" },
|
|
37
|
+
{ code: "bizservice-method-config-invalid", action: "methodConfig 需要 httpType/requestBodyType/url/frontEndExtensionEnable 四键" },
|
|
38
|
+
{ code: "bizservice-parameter-face-invalid", action: "每个参数补 configJson.position;URL_VARIABLE 换 QUERY_PARAMS/REQUEST_BODY" },
|
|
39
|
+
{ code: "bizservice-required-field-missing", action: "name/adapterCode/serviceCategoryId 是设计器必填;分类 id 不能为空" },
|
|
40
|
+
{ code: "duplicate-service", action: "serviceCode 已存在;改用 service.update" },
|
|
41
|
+
{ code: "bizservice-adapter-not-whitelisted", action: "写面仅 RESTFUL/DATA_SQL/DATA_TABLE/SAP/KAFKA/SOAP;INTERNAL 走二开扩展包" },
|
|
42
|
+
...commonRecovery,
|
|
43
|
+
],
|
|
44
|
+
requiresEnvironmentDerivedIds: true,
|
|
45
|
+
prerequisiteData: { source: "service.category.list", fields: ["category.id"] },
|
|
46
|
+
});
|
|
47
|
+
const bizserviceSelfCallCorp = Object.freeze({
|
|
48
|
+
id: "bizservice-self-call-corp",
|
|
49
|
+
title: "业务规则自调本实例:oauth_password 为基础;X-LowCode-Corpid 头视环境而定(token 是否自带 corpId,8.5+ 部分配置才需要)——非铁律,真机判定",
|
|
50
|
+
status: "offline-valid",
|
|
51
|
+
tool: "method.update",
|
|
52
|
+
args: {
|
|
53
|
+
environment,
|
|
54
|
+
serviceCode: "<service_code>",
|
|
55
|
+
methodCode: "<method_code>",
|
|
56
|
+
inputParameters: [
|
|
57
|
+
{ code: "X-LowCode-Corpid", name: "corpId头", required: false, codeType: 0, bizCode: "<corpId 常量值>", configJson: { position: "REQUEST_HEADER" } },
|
|
58
|
+
],
|
|
59
|
+
},
|
|
60
|
+
preconditions: [
|
|
61
|
+
"自调本实例(commonlist.url 指回本平台 /api)鉴权以 oauth_password 为基础(Authorization Bearer)。**X-LowCode-Corpid 头非铁律**:token 自带 corpId claim 的环境(生产多数)不配任何 corpid;token corpId=null 的环境(本沙盒 api 客户端;8.5+ 部分配置)缺头会 HTTP 200 但响应体 errcode:50000(corpId can not be blank,r5 实测 2026-10-10)。",
|
|
62
|
+
"**判定法(先做再配)**:带 token 直调一次扩展端点看**响应体 errcode**(HTTP 200 不代表成功,平台错误包在体里);errcode:0 则不配 corpid;errcode:50000 则按本配方补方法参数(code=X-LowCode-Corpid、configJson.position=REQUEST_HEADER、codeType:0 CONST、值放 bizCode——平台注入,调用方无需传;手动 curl 加请求头即可)。",
|
|
63
|
+
"出站第三方接口按对方要求配鉴权,与本配方无关。",
|
|
64
|
+
],
|
|
65
|
+
conditionalRequirements: [
|
|
66
|
+
"**参数 code 必须精确等于 `X-LowCode-Corpid`**——适配器按「参数 code = header 名」加入请求头(headerParam.add(key, value))。",
|
|
67
|
+
"**corpid 传递有两种实证形状**:①方法级入参 code 为 X-LowCode-Corpid、configJson.position 为 REQUEST_HEADER 整数 2(r3-wms 实证可用);②规则 BIZ_ACTION 的 inputMappings 加 CONST 映射(serviceMethodParameterCode 为 X-LowCode-Corpid、codeType 为 0、bizCode 放真实 corpId——r4-fin 实证:该环境下方法级 position:2 注入为空头值 [\"\"],此形状才生效)。**先用 ②,双跑验证头值;①失效(头空)就换 ②**。CONST 值必须放 bizCode(平台只读 bizCode)。",
|
|
68
|
+
"**corpid 头非空即可(r6-onlinejs R19 实证)**:沙盒 token corpId=null 时,全 0 corpId 头(RELEVANCE-0000…)也 errcode:0;仅空头才 50000。多租户路由才需真值。凭据值不可从读回抄(读面按 ticket 115 掩码——0.4.16 起为结构化 {masked:true,hint},旧版 ***),必须用任务环境事实真值(doctor 显示的 corpId、任务提供的 client_secret)。",
|
|
69
|
+
"configJson.position 用 REQUEST_HEADER 名即可(工具写侧编码为整数索引 2;wire 上是整数——写名字平台侧反序列化失败、header 根本不进,源码 @JsonCreator get(int))。",
|
|
70
|
+
"BIZ_ACTION 节点调用该方法**无需传该常量参数**(方法级常量由平台注入);只需照常映射业务参数。",
|
|
71
|
+
],
|
|
72
|
+
priorToolReferences: [{ tool: "method.get", args: { environment, serviceCode: "<service_code>", methodCode: "<method_code>" }, purpose: "取现有参数面,update 时整组带回(含本常量头)" }],
|
|
73
|
+
dryRun: { supported: true, command: `omc call method.update --env ${environment} --dry-run --args '<recipe.args>'`, notes: "dry-run 校验参数面/CONST 形状,零 wire" },
|
|
74
|
+
expectedReadback: { readback: { methodPresent: true, corpHeaderParam: "code=X-LowCode-Corpid position=REQUEST_HEADER(2) codeType=0 bizCode=<corpId>" }, next: ["BIZ_ACTION 规则触发后 E2E:被调接口不再回 50000 corpId can not be blank"] },
|
|
75
|
+
refusalRecovery: [
|
|
76
|
+
{ code: "bizservice-parameter-face-invalid", action: "常量头也是参数:configJson.position=REQUEST_HEADER 必带" },
|
|
77
|
+
{ code: "runtime-50000-corpId-blank", action: "header 仍空 = 常量值放错槽(须 bizCode)或参数 code 不是精确的 X-LowCode-Corpid;method.get 读回核对" },
|
|
78
|
+
{ code: "bizservice-auth-credential-placeholder", action: "凭据被掩码/占位值守卫拦截——读回掩码 *** 或自造 RELEVANCE-xxx/全 0 不可注册;凭据必须从任务环境事实取真值(doctor 显示的 corpId、任务提供的 client_secret),不可从读回抄" },
|
|
79
|
+
...commonRecovery,
|
|
80
|
+
],
|
|
81
|
+
requiresEnvironmentDerivedIds: false,
|
|
82
|
+
});
|
|
83
|
+
export const B2_METADATA = Object.freeze({
|
|
84
|
+
"service.register": Object.freeze({ recipes: [restfulQueryService], relatedTools: ["service.category.list", "service.adapter_config", "service.get", "method.get"] }),
|
|
85
|
+
"method.update": Object.freeze({ recipes: [bizserviceSelfCallCorp], relatedTools: ["method.get", "method.create", "service.get"] }),
|
|
86
|
+
});
|
|
87
|
+
//# sourceMappingURL=b2-registration.js.map
|