apaas-oapi-client 0.1.40 → 1.0.0
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 +33 -7
- package/UserManual.md +115 -1
- package/dist/field-schema-rules.d.ts +36 -0
- package/dist/field-types.d.ts +2 -2
- package/dist/index.d.ts +332 -4
- package/dist/index.js +1068 -5
- package/dist/schema-utils.d.ts +194 -0
- package/package.json +3 -3
- package/skills/apaas-function-flow/SKILL.md +47 -2
- package/skills/apaas-function-flow/agents/openai.yaml +2 -2
- package/skills/apaas-object/SKILL.md +41 -2
- package/skills/apaas-object/agents/openai.yaml +2 -2
- package/skills/apaas-object/references/id-cursor-pagination.md +64 -0
- package/skills/apaas-schema/SKILL.md +43 -22
- package/skills/apaas-schema/references/field-schema-rules.md +24 -1
- package/skills/apaas-schema/references/schema-maintenance-sop.md +18 -42
- package/skills/apaas-shared/SKILL.md +5 -2
- package/skills/apaas-shared/agents/openai.yaml +2 -2
- package/skills/apaas-shared/references/openapi-coverage.md +33 -0
- package/skills/apaas-shared/references/openapi-error-codes.md +55 -0
- package/src/FIELD_SCHEMA_RULES.md +18 -1
- package/src/field-schema-rules.ts +95 -1
- package/src/field-types.ts +2 -2
- package/src/index.ts +843 -8
- package/src/schema-utils.ts +792 -0
package/dist/index.js
CHANGED
|
@@ -778,12 +778,34 @@ const OPTION_COLOR_LIST = [
|
|
|
778
778
|
'blueMagenta',
|
|
779
779
|
'grey'
|
|
780
780
|
];
|
|
781
|
+
const OPTION_COLOR_CODE_BY_NAME = {
|
|
782
|
+
blue: 'B',
|
|
783
|
+
cyan: 'W',
|
|
784
|
+
green: 'G',
|
|
785
|
+
yellow: 'Y',
|
|
786
|
+
orange: 'O',
|
|
787
|
+
red: 'R',
|
|
788
|
+
magenta: 'V',
|
|
789
|
+
purple: 'P',
|
|
790
|
+
blueMagenta: 'I',
|
|
791
|
+
grey: 'N'
|
|
792
|
+
};
|
|
793
|
+
const OPTION_COLOR_NAME_BY_CODE = Object.fromEntries(Object.entries(OPTION_COLOR_CODE_BY_NAME).map(([name, code]) => [code, name]));
|
|
781
794
|
function getOptionColor(index) {
|
|
782
795
|
if (!Number.isInteger(index) || index < 0) {
|
|
783
796
|
throw new Error('Option color index must be a non-negative integer.');
|
|
784
797
|
}
|
|
785
798
|
return OPTION_COLOR_LIST[index % OPTION_COLOR_LIST.length];
|
|
786
799
|
}
|
|
800
|
+
function getOptionColorCode(color) {
|
|
801
|
+
return OPTION_COLOR_CODE_BY_NAME[color];
|
|
802
|
+
}
|
|
803
|
+
function normalizeOptionColorForSchema(color) {
|
|
804
|
+
if (typeof color !== 'string') {
|
|
805
|
+
return color;
|
|
806
|
+
}
|
|
807
|
+
return OPTION_COLOR_CODE_BY_NAME[color] || color;
|
|
808
|
+
}
|
|
787
809
|
const OPTION_COLOR_RULES = {
|
|
788
810
|
allowedColors: OPTION_COLOR_LIST,
|
|
789
811
|
assignment: 'Use OPTION_COLOR_LIST in order and cycle from the beginning when options exceed 10.',
|
|
@@ -804,6 +826,8 @@ const OPTION_COLOR_RULES = {
|
|
|
804
826
|
typeName: 'enum',
|
|
805
827
|
optionsPath: 'type.settings.options',
|
|
806
828
|
colorPath: 'type.settings.options[].color',
|
|
829
|
+
colorInput: 'SDK accepts metadata color names and normalizes them to OpenAPI color codes before writing.',
|
|
830
|
+
colorCodeByName: OPTION_COLOR_CODE_BY_NAME,
|
|
807
831
|
sourcePath: 'type.settings.option_source',
|
|
808
832
|
globalOptionPath: 'type.settings.global_option_api_name'
|
|
809
833
|
}
|
|
@@ -889,7 +913,7 @@ const FIELD_SCHEMA_RULES = [
|
|
|
889
913
|
}
|
|
890
914
|
]
|
|
891
915
|
},
|
|
892
|
-
notes: `Do not send create type as \`option\`. Metadata returns optionList/optionSource/globalOptionAPIName; create/update expects options/option_source/global_option_api_name.
|
|
916
|
+
notes: `Do not send create type as \`option\`. Metadata returns optionList/optionSource/globalOptionAPIName; create/update expects options/option_source/global_option_api_name. The SDK accepts metadata color names and sends OpenAPI color codes (${Object.entries(OPTION_COLOR_CODE_BY_NAME).map(([name, code]) => `${name}=${code}`).join(', ')}).`
|
|
893
917
|
},
|
|
894
918
|
{
|
|
895
919
|
metadataType: 'boolean',
|
|
@@ -1033,6 +1057,35 @@ const SCHEMA_TYPE_MISMATCHES = FIELD_SCHEMA_RULES
|
|
|
1033
1057
|
metadataType: rule.metadataType,
|
|
1034
1058
|
schemaType: rule.schemaType
|
|
1035
1059
|
}));
|
|
1060
|
+
const SQL_TYPE_TO_SCHEMA_TYPE = [
|
|
1061
|
+
{ sqlPattern: 'VARCHAR\\(\\d+\\)|CHAR\\(\\d+\\)', schemaType: 'text', settingsMapping: 'max_length from (n), multiline: false' },
|
|
1062
|
+
{ sqlPattern: 'TEXT|LONGTEXT|MEDIUMTEXT|TINYTEXT|CLOB', schemaType: 'text', settingsMapping: 'multiline: true, max_length: 100000' },
|
|
1063
|
+
{ sqlPattern: 'INT|INTEGER|BIGINT|SMALLINT|TINYINT(?!\\(1\\))|MEDIUMINT|SERIAL', schemaType: 'bigint', settingsMapping: 'required/unique from constraints' },
|
|
1064
|
+
{ sqlPattern: 'FLOAT|DOUBLE|REAL', schemaType: 'float', settingsMapping: 'decimal_places_number: 2' },
|
|
1065
|
+
{ sqlPattern: 'DECIMAL\\(\\d+,\\d+\\)|NUMERIC\\(\\d+,\\d+\\)', schemaType: 'decimal', settingsMapping: 'decimal_places from scale (s)' },
|
|
1066
|
+
{ sqlPattern: 'DATE', schemaType: 'date', settingsMapping: 'required from constraints' },
|
|
1067
|
+
{ sqlPattern: 'DATETIME|TIMESTAMP', schemaType: 'datetime', settingsMapping: 'required from constraints' },
|
|
1068
|
+
{ sqlPattern: 'BOOLEAN|BOOL|TINYINT\\(1\\)|BIT', schemaType: 'boolean', settingsMapping: 'default_value from DEFAULT' },
|
|
1069
|
+
{ sqlPattern: 'ENUM\\(.*\\)', schemaType: 'enum', settingsMapping: 'options from enum values, colors auto-assigned with getOptionColor(index)' },
|
|
1070
|
+
{ sqlPattern: 'BLOB|BINARY|VARBINARY|LONGBLOB|MEDIUMBLOB', schemaType: 'attachment', settingsMapping: 'any_type: true' },
|
|
1071
|
+
{ sqlPattern: 'JSON', schemaType: 'richText', settingsMapping: 'only when JSON stores rich text content' }
|
|
1072
|
+
];
|
|
1073
|
+
const COLUMN_NAME_SEMANTIC_RULES = [
|
|
1074
|
+
{ columnPattern: '(^|_)(e?mail)(s?$|_)', schemaType: 'email', notes: 'Column name contains email/mail' },
|
|
1075
|
+
{ columnPattern: '(^|_)(phone|mobile|tel)(s?$|_)', schemaType: 'phone', notes: 'Column name contains phone/mobile/tel' },
|
|
1076
|
+
{ columnPattern: '(^|_)(avatar|logo|profile_image)(s?$|_)', schemaType: 'avatar', notes: 'Column name contains avatar/logo' },
|
|
1077
|
+
{ columnPattern: '(^|_)(region|province|city|district|address)(s?$|_)', schemaType: 'region', notes: 'Column name implies geographic data' }
|
|
1078
|
+
];
|
|
1079
|
+
const SQL_CONSTRAINT_TO_SETTINGS = [
|
|
1080
|
+
{ sqlConstraint: 'NOT NULL', settingsField: 'required', settingsValue: 'true', notes: 'Maps to required: true' },
|
|
1081
|
+
{ sqlConstraint: 'UNIQUE', settingsField: 'unique', settingsValue: 'true', notes: 'Maps to unique: true' },
|
|
1082
|
+
{ sqlConstraint: 'PRIMARY KEY', settingsField: '-', settingsValue: '-', notes: 'Ignored: aPaaS uses system _id' },
|
|
1083
|
+
{ sqlConstraint: 'AUTO_INCREMENT', settingsField: '-', settingsValue: '-', notes: 'Ignored: aPaaS _id auto-increments. For business serial numbers, use auto_number' },
|
|
1084
|
+
{ sqlConstraint: 'FOREIGN KEY', settingsField: 'referenced_object_api_name', settingsValue: '(target table)', notes: 'Convert to lookup field' },
|
|
1085
|
+
{ sqlConstraint: 'DEFAULT', settingsField: 'default_value', settingsValue: '(value)', notes: 'Only boolean type supports default_value in aPaaS' },
|
|
1086
|
+
{ sqlConstraint: 'CHECK', settingsField: '-', settingsValue: '-', notes: 'Not supported in aPaaS, handle in application logic' },
|
|
1087
|
+
{ sqlConstraint: 'INDEX', settingsField: '-', settingsValue: '-', notes: 'Not applicable, aPaaS manages indexing automatically' }
|
|
1088
|
+
];
|
|
1036
1089
|
const BATCH_UPDATE_REQUIREMENTS = {
|
|
1037
1090
|
add: 'Use operator=add with full field definition.',
|
|
1038
1091
|
replace: 'Use operator=replace and include full `type` (name + settings). Label-only replace fails.',
|
|
@@ -1044,6 +1097,488 @@ const BATCH_UPDATE_REQUIREMENTS = {
|
|
|
1044
1097
|
referenceFieldConstraint: 'reference_field only works with single lookup (`multiple: false`).'
|
|
1045
1098
|
};
|
|
1046
1099
|
|
|
1100
|
+
const SCHEMA_BATCH_SIZE = 10;
|
|
1101
|
+
function isSystemSchemaName(apiName) {
|
|
1102
|
+
return apiName.startsWith('_');
|
|
1103
|
+
}
|
|
1104
|
+
function normalizeSchemaObjectsForWrite(objects) {
|
|
1105
|
+
return objects.map((object) => {
|
|
1106
|
+
if (!object.fields) {
|
|
1107
|
+
return { ...object };
|
|
1108
|
+
}
|
|
1109
|
+
return {
|
|
1110
|
+
...object,
|
|
1111
|
+
fields: object.fields.map((field) => normalizeSchemaFieldForWrite(field))
|
|
1112
|
+
};
|
|
1113
|
+
});
|
|
1114
|
+
}
|
|
1115
|
+
function normalizeSchemaFieldForWrite(field) {
|
|
1116
|
+
var _a, _b;
|
|
1117
|
+
const settings = (_a = field.type) === null || _a === void 0 ? void 0 : _a.settings;
|
|
1118
|
+
if (((_b = field.type) === null || _b === void 0 ? void 0 : _b.name) !== 'enum' || !Array.isArray(settings === null || settings === void 0 ? void 0 : settings.options)) {
|
|
1119
|
+
return { ...field };
|
|
1120
|
+
}
|
|
1121
|
+
return {
|
|
1122
|
+
...field,
|
|
1123
|
+
type: {
|
|
1124
|
+
...field.type,
|
|
1125
|
+
settings: {
|
|
1126
|
+
...settings,
|
|
1127
|
+
options: settings.options.map((option) => {
|
|
1128
|
+
if (!option || typeof option !== 'object' || !('color' in option)) {
|
|
1129
|
+
return option;
|
|
1130
|
+
}
|
|
1131
|
+
return {
|
|
1132
|
+
...option,
|
|
1133
|
+
color: normalizeOptionColorForSchema(option.color)
|
|
1134
|
+
};
|
|
1135
|
+
})
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
};
|
|
1139
|
+
}
|
|
1140
|
+
function validateSchemaResponse(result, context = 'schema', options = {}) {
|
|
1141
|
+
var _a, _b, _c, _d;
|
|
1142
|
+
const failures = [];
|
|
1143
|
+
if (!result) {
|
|
1144
|
+
failures.push({
|
|
1145
|
+
layer: 'request',
|
|
1146
|
+
context,
|
|
1147
|
+
code: 'NO_RESULT',
|
|
1148
|
+
message: `${context} request failed: empty response`
|
|
1149
|
+
});
|
|
1150
|
+
return { ok: false, result, failures };
|
|
1151
|
+
}
|
|
1152
|
+
if (String(result.code) !== '0') {
|
|
1153
|
+
failures.push({
|
|
1154
|
+
layer: 'request',
|
|
1155
|
+
context,
|
|
1156
|
+
code: result.code === undefined ? 'undefined' : String(result.code),
|
|
1157
|
+
message: `${context} request failed: ${result.code} ${result.msg || result.message || ''}`.trim()
|
|
1158
|
+
});
|
|
1159
|
+
}
|
|
1160
|
+
if (result.data === null && !options.allowDataNull) {
|
|
1161
|
+
failures.push({
|
|
1162
|
+
layer: 'silent',
|
|
1163
|
+
context,
|
|
1164
|
+
code: 'DATA_NULL',
|
|
1165
|
+
message: `${context} silently failed: result.code is 0 but result.data is null`
|
|
1166
|
+
});
|
|
1167
|
+
}
|
|
1168
|
+
for (const item of ((_a = result.data) === null || _a === void 0 ? void 0 : _a.items) || []) {
|
|
1169
|
+
const itemCode = (_b = item.status) === null || _b === void 0 ? void 0 : _b.code;
|
|
1170
|
+
if (itemCode === undefined && options.requireItemStatus) {
|
|
1171
|
+
failures.push({
|
|
1172
|
+
layer: 'item',
|
|
1173
|
+
context,
|
|
1174
|
+
code: 'MISSING_STATUS',
|
|
1175
|
+
apiName: getItemApiName(item),
|
|
1176
|
+
item,
|
|
1177
|
+
message: `${context} item status is missing: ${getItemApiName(item) || 'unknown'}`
|
|
1178
|
+
});
|
|
1179
|
+
continue;
|
|
1180
|
+
}
|
|
1181
|
+
if (itemCode !== undefined && String(itemCode) !== '0') {
|
|
1182
|
+
failures.push({
|
|
1183
|
+
layer: 'item',
|
|
1184
|
+
context,
|
|
1185
|
+
code: String(itemCode),
|
|
1186
|
+
apiName: getItemApiName(item),
|
|
1187
|
+
item,
|
|
1188
|
+
message: `${context} item failed: ${getItemApiName(item) || 'unknown'} ${((_c = item.status) === null || _c === void 0 ? void 0 : _c.message) || ((_d = item.status) === null || _d === void 0 ? void 0 : _d.msg) || ''}`.trim()
|
|
1189
|
+
});
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
return { ok: failures.length === 0, result, failures };
|
|
1193
|
+
}
|
|
1194
|
+
function checkSchemaResponse(result, context = 'schema', options) {
|
|
1195
|
+
const validation = validateSchemaResponse(result, context, options);
|
|
1196
|
+
if (!validation.ok) {
|
|
1197
|
+
const error = new Error(validation.failures.map((failure) => failure.message).join('; '));
|
|
1198
|
+
error.failures = validation.failures;
|
|
1199
|
+
throw error;
|
|
1200
|
+
}
|
|
1201
|
+
return result;
|
|
1202
|
+
}
|
|
1203
|
+
async function batchExecute(items, fn, options = {}) {
|
|
1204
|
+
var _a;
|
|
1205
|
+
const batchSize = (_a = options.batchSize) !== null && _a !== void 0 ? _a : SCHEMA_BATCH_SIZE;
|
|
1206
|
+
if (!Number.isInteger(batchSize) || batchSize <= 0) {
|
|
1207
|
+
throw new Error('batchSize must be a positive integer.');
|
|
1208
|
+
}
|
|
1209
|
+
const batchCount = Math.ceil(items.length / batchSize);
|
|
1210
|
+
const results = [];
|
|
1211
|
+
const failures = [];
|
|
1212
|
+
for (let start = 0; start < items.length; start += batchSize) {
|
|
1213
|
+
const batch = items.slice(start, start + batchSize);
|
|
1214
|
+
const batchIndex = Math.floor(start / batchSize) + 1;
|
|
1215
|
+
const info = {
|
|
1216
|
+
batchIndex,
|
|
1217
|
+
batchCount,
|
|
1218
|
+
start,
|
|
1219
|
+
end: start + batch.length,
|
|
1220
|
+
batchSize: batch.length
|
|
1221
|
+
};
|
|
1222
|
+
const context = `${options.context || 'schema batch'} [${batchIndex}/${batchCount}]`;
|
|
1223
|
+
try {
|
|
1224
|
+
const result = await fn(batch, info);
|
|
1225
|
+
results.push(result);
|
|
1226
|
+
if (options.checkResponse !== false) {
|
|
1227
|
+
const validation = validateSchemaResponse(result, context, options.responseOptions);
|
|
1228
|
+
failures.push(...validation.failures);
|
|
1229
|
+
if (!validation.ok && !options.continueOnError) {
|
|
1230
|
+
const error = new Error(validation.failures.map((failure) => failure.message).join('; '));
|
|
1231
|
+
error.failures = validation.failures;
|
|
1232
|
+
throw error;
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
catch (error) {
|
|
1237
|
+
if (!options.continueOnError) {
|
|
1238
|
+
throw error;
|
|
1239
|
+
}
|
|
1240
|
+
failures.push({
|
|
1241
|
+
layer: 'request',
|
|
1242
|
+
context,
|
|
1243
|
+
code: 'EXCEPTION',
|
|
1244
|
+
message: error instanceof Error ? error.message : String(error)
|
|
1245
|
+
});
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
return {
|
|
1249
|
+
ok: failures.length === 0,
|
|
1250
|
+
total: items.length,
|
|
1251
|
+
batchSize,
|
|
1252
|
+
batchCount,
|
|
1253
|
+
results,
|
|
1254
|
+
failures
|
|
1255
|
+
};
|
|
1256
|
+
}
|
|
1257
|
+
function splitSchemaFieldsByDependency(fields) {
|
|
1258
|
+
const baseFields = [];
|
|
1259
|
+
const lookupFields = [];
|
|
1260
|
+
const referenceFields = [];
|
|
1261
|
+
for (const field of fields) {
|
|
1262
|
+
const typeName = getSchemaFieldTypeName(field);
|
|
1263
|
+
if (typeName === 'reference_field' || typeName === 'referenceField') {
|
|
1264
|
+
referenceFields.push(field);
|
|
1265
|
+
}
|
|
1266
|
+
else if (typeName === 'lookup' || typeName === 'lookup_multi') {
|
|
1267
|
+
lookupFields.push(field);
|
|
1268
|
+
}
|
|
1269
|
+
else {
|
|
1270
|
+
baseFields.push(field);
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
return { baseFields, lookupFields, referenceFields };
|
|
1274
|
+
}
|
|
1275
|
+
async function createSchemaObjectShells(client, objects, options = {}) {
|
|
1276
|
+
assertNoSystemObjects(objects.map((object) => object.api_name), 'createSchemaObjectShells');
|
|
1277
|
+
const existingNames = options.skipExisting === false
|
|
1278
|
+
? new Set()
|
|
1279
|
+
: await getExistingObjectNames(client);
|
|
1280
|
+
const shells = objects
|
|
1281
|
+
.filter((object) => !existingNames.has(object.api_name))
|
|
1282
|
+
.map(toShellObject);
|
|
1283
|
+
const result = {
|
|
1284
|
+
requested: objects.map((object) => object.api_name),
|
|
1285
|
+
created: shells.map((object) => object.api_name),
|
|
1286
|
+
skippedExisting: objects
|
|
1287
|
+
.filter((object) => existingNames.has(object.api_name))
|
|
1288
|
+
.map((object) => object.api_name)
|
|
1289
|
+
};
|
|
1290
|
+
if (shells.length === 0) {
|
|
1291
|
+
return result;
|
|
1292
|
+
}
|
|
1293
|
+
result.batches = await batchExecute(shells, (batch) => client.schema.create({ objects: batch }), {
|
|
1294
|
+
batchSize: options.batchSize,
|
|
1295
|
+
context: options.context || 'schema.createShells',
|
|
1296
|
+
continueOnError: options.continueOnError,
|
|
1297
|
+
checkResponse: options.checkResponse,
|
|
1298
|
+
responseOptions: options.responseOptions
|
|
1299
|
+
});
|
|
1300
|
+
return result;
|
|
1301
|
+
}
|
|
1302
|
+
async function addFieldsIdempotent(client, objectName, fieldsToAdd, options = {}) {
|
|
1303
|
+
assertNoSystemObjects([objectName], 'addFieldsIdempotent');
|
|
1304
|
+
assertNoSystemFields(fieldsToAdd.map((field) => field.api_name), `addFieldsIdempotent(${objectName})`);
|
|
1305
|
+
const existingNames = options.skipExisting === false
|
|
1306
|
+
? new Set()
|
|
1307
|
+
: await getExistingFieldNames(client, objectName);
|
|
1308
|
+
const newFields = fieldsToAdd.filter((field) => !existingNames.has(field.api_name)).map(toAddField);
|
|
1309
|
+
const skippedFields = fieldsToAdd
|
|
1310
|
+
.filter((field) => existingNames.has(field.api_name))
|
|
1311
|
+
.map((field) => field.api_name);
|
|
1312
|
+
if (newFields.length === 0) {
|
|
1313
|
+
return {
|
|
1314
|
+
objectName,
|
|
1315
|
+
addedFields: [],
|
|
1316
|
+
skippedFields
|
|
1317
|
+
};
|
|
1318
|
+
}
|
|
1319
|
+
const result = await client.schema.update({
|
|
1320
|
+
objects: [{ api_name: objectName, fields: newFields }]
|
|
1321
|
+
});
|
|
1322
|
+
if (options.checkResponse !== false) {
|
|
1323
|
+
checkSchemaResponse(result, options.context || `schema.addFieldsIdempotent(${objectName})`, options.responseOptions);
|
|
1324
|
+
}
|
|
1325
|
+
return {
|
|
1326
|
+
objectName,
|
|
1327
|
+
addedFields: newFields.map((field) => field.api_name),
|
|
1328
|
+
skippedFields,
|
|
1329
|
+
result
|
|
1330
|
+
};
|
|
1331
|
+
}
|
|
1332
|
+
async function createSchemaObjectsInStages(client, objects, options = {}) {
|
|
1333
|
+
const context = options.context || 'schema.createWithStages';
|
|
1334
|
+
const shells = await createSchemaObjectShells(client, objects, {
|
|
1335
|
+
...options,
|
|
1336
|
+
context: `${context}.shells`
|
|
1337
|
+
});
|
|
1338
|
+
const baseFields = [];
|
|
1339
|
+
const lookupFields = [];
|
|
1340
|
+
const referenceFields = [];
|
|
1341
|
+
for (const object of objects) {
|
|
1342
|
+
assertNoSystemFields((object.fields || []).map((field) => field.api_name), `${context}(${object.api_name})`);
|
|
1343
|
+
const split = splitSchemaFieldsByDependency(object.fields || []);
|
|
1344
|
+
if (split.baseFields.length > 0) {
|
|
1345
|
+
baseFields.push(await addFieldsIdempotent(client, object.api_name, split.baseFields, {
|
|
1346
|
+
context: `${context}.baseFields(${object.api_name})`,
|
|
1347
|
+
skipExisting: options.skipExisting,
|
|
1348
|
+
checkResponse: options.checkResponse,
|
|
1349
|
+
responseOptions: options.responseOptions
|
|
1350
|
+
}));
|
|
1351
|
+
}
|
|
1352
|
+
if (split.lookupFields.length > 0) {
|
|
1353
|
+
lookupFields.push(await addFieldsIdempotent(client, object.api_name, split.lookupFields, {
|
|
1354
|
+
context: `${context}.lookupFields(${object.api_name})`,
|
|
1355
|
+
skipExisting: options.skipExisting,
|
|
1356
|
+
checkResponse: options.checkResponse,
|
|
1357
|
+
responseOptions: options.responseOptions
|
|
1358
|
+
}));
|
|
1359
|
+
}
|
|
1360
|
+
if (split.referenceFields.length > 0) {
|
|
1361
|
+
referenceFields.push(await addFieldsIdempotent(client, object.api_name, split.referenceFields, {
|
|
1362
|
+
context: `${context}.referenceFields(${object.api_name})`,
|
|
1363
|
+
skipExisting: options.skipExisting,
|
|
1364
|
+
checkResponse: options.checkResponse,
|
|
1365
|
+
responseOptions: options.responseOptions
|
|
1366
|
+
}));
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
const result = {
|
|
1370
|
+
shells,
|
|
1371
|
+
baseFields,
|
|
1372
|
+
lookupFields,
|
|
1373
|
+
referenceFields
|
|
1374
|
+
};
|
|
1375
|
+
const finalSettings = options.updateFinalSettings === false
|
|
1376
|
+
? []
|
|
1377
|
+
: objects
|
|
1378
|
+
.filter((object) => object.settings && Object.keys(object.settings).length > 0)
|
|
1379
|
+
.map((object) => ({ api_name: object.api_name, settings: object.settings }));
|
|
1380
|
+
if (finalSettings.length > 0) {
|
|
1381
|
+
result.finalSettings = await batchExecute(finalSettings, (batch) => client.schema.update({ objects: batch }), {
|
|
1382
|
+
batchSize: options.batchSize,
|
|
1383
|
+
context: `${context}.finalSettings`,
|
|
1384
|
+
continueOnError: options.continueOnError,
|
|
1385
|
+
checkResponse: options.checkResponse,
|
|
1386
|
+
responseOptions: {
|
|
1387
|
+
...options.responseOptions,
|
|
1388
|
+
allowDataNull: true
|
|
1389
|
+
}
|
|
1390
|
+
});
|
|
1391
|
+
}
|
|
1392
|
+
if (options.verify !== false) {
|
|
1393
|
+
result.verification = await verifySchemaObjects(client, objects.map((object) => object.api_name), { includeMarkdown: options.includeMarkdown });
|
|
1394
|
+
}
|
|
1395
|
+
return result;
|
|
1396
|
+
}
|
|
1397
|
+
async function verifySchemaObjects(client, objectNames, options = {}) {
|
|
1398
|
+
var _a, _b;
|
|
1399
|
+
const allObjects = await client.object.listWithIterator();
|
|
1400
|
+
const objects = [];
|
|
1401
|
+
for (const objectName of objectNames) {
|
|
1402
|
+
const exists = Boolean((_a = allObjects.items) === null || _a === void 0 ? void 0 : _a.find((object) => object.apiName === objectName || object.api_name === objectName));
|
|
1403
|
+
if (!exists) {
|
|
1404
|
+
objects.push({
|
|
1405
|
+
objectName,
|
|
1406
|
+
exists: false,
|
|
1407
|
+
fields: [],
|
|
1408
|
+
customFields: []
|
|
1409
|
+
});
|
|
1410
|
+
continue;
|
|
1411
|
+
}
|
|
1412
|
+
const fieldResult = await client.object.metadata.fields({ object_name: objectName });
|
|
1413
|
+
if (fieldResult.code !== undefined && String(fieldResult.code) !== '0') {
|
|
1414
|
+
throw new Error(`verifySchemaObjects(${objectName}) failed: ${fieldResult.code} ${fieldResult.msg || fieldResult.message || ''}`.trim());
|
|
1415
|
+
}
|
|
1416
|
+
const fields = ((_b = fieldResult.data) === null || _b === void 0 ? void 0 : _b.fields) || [];
|
|
1417
|
+
objects.push({
|
|
1418
|
+
objectName,
|
|
1419
|
+
exists: true,
|
|
1420
|
+
fields,
|
|
1421
|
+
customFields: fields.filter((field) => !isSystemSchemaName(field.apiName || field.api_name || ''))
|
|
1422
|
+
});
|
|
1423
|
+
}
|
|
1424
|
+
const result = { objects };
|
|
1425
|
+
if (options.includeMarkdown && client.object.metadata.export2markdown) {
|
|
1426
|
+
result.markdown = await client.object.metadata.export2markdown({ object_names: objectNames });
|
|
1427
|
+
}
|
|
1428
|
+
return result;
|
|
1429
|
+
}
|
|
1430
|
+
function buildFieldRemovalPlan(fieldsByObject) {
|
|
1431
|
+
const referenceFieldObjects = new Map();
|
|
1432
|
+
const lookupObjects = new Map();
|
|
1433
|
+
const otherFieldObjects = new Map();
|
|
1434
|
+
for (const [objectName, fields] of Object.entries(fieldsByObject)) {
|
|
1435
|
+
for (const field of fields) {
|
|
1436
|
+
const apiName = field.api_name || field.apiName;
|
|
1437
|
+
if (!apiName || isSystemSchemaName(apiName)) {
|
|
1438
|
+
continue;
|
|
1439
|
+
}
|
|
1440
|
+
const target = getRemovalGroup(field, referenceFieldObjects, lookupObjects, otherFieldObjects);
|
|
1441
|
+
const existing = target.get(objectName) || [];
|
|
1442
|
+
existing.push({ operator: 'remove', api_name: apiName });
|
|
1443
|
+
target.set(objectName, existing);
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
return {
|
|
1447
|
+
referenceFieldObjects: mapRemovalObjects(referenceFieldObjects),
|
|
1448
|
+
lookupObjects: mapRemovalObjects(lookupObjects),
|
|
1449
|
+
otherFieldObjects: mapRemovalObjects(otherFieldObjects)
|
|
1450
|
+
};
|
|
1451
|
+
}
|
|
1452
|
+
async function deleteAllCustomObjects(client, options = {}) {
|
|
1453
|
+
var _a;
|
|
1454
|
+
if (options.confirm !== true) {
|
|
1455
|
+
throw new Error('deleteAllCustomObjects requires { confirm: true }.');
|
|
1456
|
+
}
|
|
1457
|
+
const context = options.context || 'schema.deleteAllCustomObjects';
|
|
1458
|
+
const allObjects = await client.object.listWithIterator();
|
|
1459
|
+
const customObjects = (allObjects.items || []).filter((object) => !isSystemSchemaName(object.apiName || object.api_name || ''));
|
|
1460
|
+
const objectNames = customObjects.map((object) => object.apiName || object.api_name);
|
|
1461
|
+
const fieldsByObject = {};
|
|
1462
|
+
for (const objectName of objectNames) {
|
|
1463
|
+
const fieldResult = await client.object.metadata.fields({ object_name: objectName });
|
|
1464
|
+
if (fieldResult.code !== undefined && String(fieldResult.code) !== '0') {
|
|
1465
|
+
throw new Error(`${context}.readFields(${objectName}) failed: ${fieldResult.code} ${fieldResult.msg || fieldResult.message || ''}`.trim());
|
|
1466
|
+
}
|
|
1467
|
+
fieldsByObject[objectName] = ((_a = fieldResult.data) === null || _a === void 0 ? void 0 : _a.fields) || [];
|
|
1468
|
+
}
|
|
1469
|
+
const removalPlan = buildFieldRemovalPlan(fieldsByObject);
|
|
1470
|
+
const fieldRemovalResults = [];
|
|
1471
|
+
for (const [phase, updateObjects] of [
|
|
1472
|
+
['referenceFields', removalPlan.referenceFieldObjects],
|
|
1473
|
+
['lookupFields', removalPlan.lookupObjects],
|
|
1474
|
+
['otherFields', options.removeOtherFields ? removalPlan.otherFieldObjects : []]
|
|
1475
|
+
]) {
|
|
1476
|
+
if (updateObjects.length === 0) {
|
|
1477
|
+
continue;
|
|
1478
|
+
}
|
|
1479
|
+
fieldRemovalResults.push(await batchExecute(updateObjects, (batch) => client.schema.update({ objects: batch }), {
|
|
1480
|
+
batchSize: options.batchSize,
|
|
1481
|
+
context: `${context}.${phase}`,
|
|
1482
|
+
continueOnError: options.continueOnError,
|
|
1483
|
+
checkResponse: options.checkResponse,
|
|
1484
|
+
responseOptions: options.responseOptions
|
|
1485
|
+
}));
|
|
1486
|
+
}
|
|
1487
|
+
const result = {
|
|
1488
|
+
deletedObjects: objectNames,
|
|
1489
|
+
removalPlan,
|
|
1490
|
+
fieldRemovalResults
|
|
1491
|
+
};
|
|
1492
|
+
if (objectNames.length > 0) {
|
|
1493
|
+
result.deleteResults = await batchExecute(objectNames, (batch) => client.schema.delete({ api_names: batch }), {
|
|
1494
|
+
batchSize: options.batchSize,
|
|
1495
|
+
context: `${context}.deleteObjects`,
|
|
1496
|
+
continueOnError: options.continueOnError,
|
|
1497
|
+
checkResponse: options.checkResponse,
|
|
1498
|
+
responseOptions: {
|
|
1499
|
+
...options.responseOptions,
|
|
1500
|
+
allowDataNull: true
|
|
1501
|
+
}
|
|
1502
|
+
});
|
|
1503
|
+
}
|
|
1504
|
+
if (options.verify !== false) {
|
|
1505
|
+
const after = await client.object.listWithIterator();
|
|
1506
|
+
result.remainingObjects = (after.items || [])
|
|
1507
|
+
.filter((object) => objectNames.includes(object.apiName || object.api_name))
|
|
1508
|
+
.map((object) => object.apiName || object.api_name);
|
|
1509
|
+
if (result.remainingObjects.length > 0) {
|
|
1510
|
+
throw new Error(`${context} verification failed: remaining objects ${result.remainingObjects.join(', ')}`);
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
return result;
|
|
1514
|
+
}
|
|
1515
|
+
function getItemApiName(item) {
|
|
1516
|
+
return item.api_name || item.apiName || item.name;
|
|
1517
|
+
}
|
|
1518
|
+
function getSchemaFieldTypeName(field) {
|
|
1519
|
+
const type = field.type;
|
|
1520
|
+
if (typeof type === 'string') {
|
|
1521
|
+
return type;
|
|
1522
|
+
}
|
|
1523
|
+
return type === null || type === void 0 ? void 0 : type.name;
|
|
1524
|
+
}
|
|
1525
|
+
function toAddField(field) {
|
|
1526
|
+
return {
|
|
1527
|
+
...field,
|
|
1528
|
+
operator: 'add'
|
|
1529
|
+
};
|
|
1530
|
+
}
|
|
1531
|
+
function toShellObject(object) {
|
|
1532
|
+
const { fields: _fields, ...shell } = object;
|
|
1533
|
+
const originalSettings = object.settings || {};
|
|
1534
|
+
return {
|
|
1535
|
+
...shell,
|
|
1536
|
+
settings: {
|
|
1537
|
+
...originalSettings,
|
|
1538
|
+
display_name: '_id',
|
|
1539
|
+
allow_search_fields: ['_id'],
|
|
1540
|
+
search_layout: []
|
|
1541
|
+
}
|
|
1542
|
+
};
|
|
1543
|
+
}
|
|
1544
|
+
async function getExistingObjectNames(client) {
|
|
1545
|
+
const result = await client.object.listWithIterator();
|
|
1546
|
+
return new Set((result.items || []).map((object) => object.apiName || object.api_name).filter(Boolean));
|
|
1547
|
+
}
|
|
1548
|
+
async function getExistingFieldNames(client, objectName) {
|
|
1549
|
+
var _a;
|
|
1550
|
+
const result = await client.object.metadata.fields({ object_name: objectName });
|
|
1551
|
+
if (result.code !== undefined && String(result.code) !== '0') {
|
|
1552
|
+
throw new Error(`getExistingFieldNames(${objectName}) failed: ${result.code} ${result.msg || result.message || ''}`.trim());
|
|
1553
|
+
}
|
|
1554
|
+
return new Set((((_a = result.data) === null || _a === void 0 ? void 0 : _a.fields) || []).map((field) => field.apiName || field.api_name).filter(Boolean));
|
|
1555
|
+
}
|
|
1556
|
+
function assertNoSystemObjects(apiNames, context) {
|
|
1557
|
+
const systemNames = apiNames.filter(isSystemSchemaName);
|
|
1558
|
+
if (systemNames.length > 0) {
|
|
1559
|
+
throw new Error(`${context} cannot modify system objects: ${systemNames.join(', ')}`);
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
function assertNoSystemFields(apiNames, context) {
|
|
1563
|
+
const systemNames = apiNames.filter(isSystemSchemaName);
|
|
1564
|
+
if (systemNames.length > 0) {
|
|
1565
|
+
throw new Error(`${context} cannot modify system fields: ${systemNames.join(', ')}`);
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
function getRemovalGroup(field, referenceFieldObjects, lookupObjects, otherFieldObjects) {
|
|
1569
|
+
const typeName = getSchemaFieldTypeName(field);
|
|
1570
|
+
if (typeName === 'reference_field' || typeName === 'referenceField') {
|
|
1571
|
+
return referenceFieldObjects;
|
|
1572
|
+
}
|
|
1573
|
+
if (typeName === 'lookup' || typeName === 'lookup_multi') {
|
|
1574
|
+
return lookupObjects;
|
|
1575
|
+
}
|
|
1576
|
+
return otherFieldObjects;
|
|
1577
|
+
}
|
|
1578
|
+
function mapRemovalObjects(fieldsByObject) {
|
|
1579
|
+
return Array.from(fieldsByObject.entries()).map(([api_name, fields]) => ({ api_name, fields }));
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1047
1582
|
/**
|
|
1048
1583
|
* 判断错误是否可重试
|
|
1049
1584
|
*/
|
|
@@ -1690,8 +2225,70 @@ class Client {
|
|
|
1690
2225
|
total: total,
|
|
1691
2226
|
msg: res.msg
|
|
1692
2227
|
};
|
|
2228
|
+
},
|
|
2229
|
+
/**
|
|
2230
|
+
* 跨对象搜索记录
|
|
2231
|
+
* @description 在最多 5 个对象中按搜索词查询记录
|
|
2232
|
+
* @param params 请求体,包含 q、search_objects、page_token、page_size、metadata 等
|
|
2233
|
+
*/
|
|
2234
|
+
recordsAcrossObjects: async (params) => {
|
|
2235
|
+
await this.ensureTokenValid();
|
|
2236
|
+
const url = `/v1/namespaces/${this.namespace}/objects/records/search`;
|
|
2237
|
+
this.log(LoggerLevel.info, `[object.search.recordsAcrossObjects] Searching records: q=${params.q}`);
|
|
2238
|
+
const res = await this.axiosInstance.post(url, params, {
|
|
2239
|
+
headers: this.authHeaders(true)
|
|
2240
|
+
});
|
|
2241
|
+
this.log(LoggerLevel.debug, `[object.search.recordsAcrossObjects] Records searched: code=${res.data.code}`);
|
|
2242
|
+
this.log(LoggerLevel.trace, `[object.search.recordsAcrossObjects] Response: ${JSON.stringify(res.data)}`);
|
|
2243
|
+
return res.data;
|
|
2244
|
+
},
|
|
2245
|
+
/**
|
|
2246
|
+
* 跨对象搜索记录 - 自动 page_token 分页
|
|
2247
|
+
*/
|
|
2248
|
+
recordsAcrossObjectsWithIterator: async (params) => {
|
|
2249
|
+
var _a, _b, _c, _d, _e, _f;
|
|
2250
|
+
const pageSize = params.page_size || 20;
|
|
2251
|
+
let pageToken = params.page_token || '';
|
|
2252
|
+
let hasMore = true;
|
|
2253
|
+
const items = [];
|
|
2254
|
+
let lastResponse = null;
|
|
2255
|
+
while (hasMore) {
|
|
2256
|
+
const res = await this.object.search.recordsAcrossObjects({
|
|
2257
|
+
...params,
|
|
2258
|
+
page_size: pageSize,
|
|
2259
|
+
page_token: pageToken
|
|
2260
|
+
});
|
|
2261
|
+
if (res.code !== '0') {
|
|
2262
|
+
this.log(LoggerLevel.error, `[object.search.recordsAcrossObjectsWithIterator] Error searching records: code=${res.code}, msg=${res.msg}`);
|
|
2263
|
+
throw new Error(res.msg || `Search failed with code ${res.code}`);
|
|
2264
|
+
}
|
|
2265
|
+
const pageItems = ((_a = res.data) === null || _a === void 0 ? void 0 : _a.items) || ((_b = res.data) === null || _b === void 0 ? void 0 : _b.records) || ((_c = res.data) === null || _c === void 0 ? void 0 : _c.search_results) || [];
|
|
2266
|
+
if (Array.isArray(pageItems)) {
|
|
2267
|
+
items.push(...pageItems);
|
|
2268
|
+
}
|
|
2269
|
+
lastResponse = res;
|
|
2270
|
+
const nextPageToken = ((_d = res.data) === null || _d === void 0 ? void 0 : _d.next_page_token) || ((_e = res.data) === null || _e === void 0 ? void 0 : _e.page_token) || '';
|
|
2271
|
+
hasMore = Boolean(((_f = res.data) === null || _f === void 0 ? void 0 : _f.has_more) && nextPageToken);
|
|
2272
|
+
pageToken = nextPageToken;
|
|
2273
|
+
}
|
|
2274
|
+
return { items, lastResponse };
|
|
1693
2275
|
}
|
|
1694
2276
|
},
|
|
2277
|
+
/**
|
|
2278
|
+
* 执行 OQL
|
|
2279
|
+
* @description 执行对象查询语言,支持匿名参数 args 和具名参数 namedArgs
|
|
2280
|
+
*/
|
|
2281
|
+
oql: async (params) => {
|
|
2282
|
+
await this.ensureTokenValid();
|
|
2283
|
+
const url = `/api/data/v1/namespaces/${this.namespace}/records/query`;
|
|
2284
|
+
this.log(LoggerLevel.info, '[object.oql] Executing OQL');
|
|
2285
|
+
const res = await this.axiosInstance.post(url, params, {
|
|
2286
|
+
headers: this.authHeaders(true)
|
|
2287
|
+
});
|
|
2288
|
+
this.log(LoggerLevel.debug, `[object.oql] OQL executed: code=${res.data.code}`);
|
|
2289
|
+
this.log(LoggerLevel.trace, `[object.oql] Response: ${JSON.stringify(res.data)}`);
|
|
2290
|
+
return res.data;
|
|
2291
|
+
},
|
|
1695
2292
|
create: {
|
|
1696
2293
|
/**
|
|
1697
2294
|
* 单条记录创建
|
|
@@ -2069,6 +2666,73 @@ class Client {
|
|
|
2069
2666
|
}
|
|
2070
2667
|
}
|
|
2071
2668
|
};
|
|
2669
|
+
/**
|
|
2670
|
+
* 常量对象模块
|
|
2671
|
+
*/
|
|
2672
|
+
this.constant = {
|
|
2673
|
+
/**
|
|
2674
|
+
* 查询常量对象列表。object_name 可取 _currency、_country、_timeZone。
|
|
2675
|
+
*/
|
|
2676
|
+
records: async (params) => {
|
|
2677
|
+
const { object_name, data = {} } = params;
|
|
2678
|
+
await this.ensureTokenValid();
|
|
2679
|
+
const url = `/api/data/v1/namespaces/${this.namespace}/objects/${object_name}/records`;
|
|
2680
|
+
this.log(LoggerLevel.info, `[constant.records] Fetching constant records: ${object_name}`);
|
|
2681
|
+
const res = await this.axiosInstance.post(url, data, {
|
|
2682
|
+
headers: this.authHeaders(true)
|
|
2683
|
+
});
|
|
2684
|
+
this.log(LoggerLevel.debug, `[constant.records] Constant records fetched: ${object_name}, code=${res.data.code}`);
|
|
2685
|
+
this.log(LoggerLevel.trace, `[constant.records] Response: ${JSON.stringify(res.data)}`);
|
|
2686
|
+
return res.data;
|
|
2687
|
+
},
|
|
2688
|
+
/**
|
|
2689
|
+
* 查询常量对象单条记录详情。
|
|
2690
|
+
*/
|
|
2691
|
+
record: async (params) => {
|
|
2692
|
+
const { object_name, record_id } = params;
|
|
2693
|
+
await this.ensureTokenValid();
|
|
2694
|
+
const url = `/api/data/v1/namespaces/${this.namespace}/objects/${object_name}/${record_id}`;
|
|
2695
|
+
this.log(LoggerLevel.info, `[constant.record] Fetching constant record: ${object_name}.${record_id}`);
|
|
2696
|
+
const res = await this.axiosInstance.get(url, {
|
|
2697
|
+
headers: this.authHeaders()
|
|
2698
|
+
});
|
|
2699
|
+
this.log(LoggerLevel.debug, `[constant.record] Constant record fetched: ${object_name}.${record_id}, code=${res.data.code}`);
|
|
2700
|
+
this.log(LoggerLevel.trace, `[constant.record] Response: ${JSON.stringify(res.data)}`);
|
|
2701
|
+
return res.data;
|
|
2702
|
+
},
|
|
2703
|
+
metadata: {
|
|
2704
|
+
/**
|
|
2705
|
+
* 获取常量对象元数据。
|
|
2706
|
+
*/
|
|
2707
|
+
fields: async (params) => {
|
|
2708
|
+
const { object_name } = params;
|
|
2709
|
+
await this.ensureTokenValid();
|
|
2710
|
+
const url = `/api/data/v1/namespaces/${this.namespace}/meta/objects/${object_name}`;
|
|
2711
|
+
this.log(LoggerLevel.info, `[constant.metadata.fields] Fetching constant metadata: ${object_name}`);
|
|
2712
|
+
const res = await this.axiosInstance.get(url, {
|
|
2713
|
+
headers: this.authHeaders()
|
|
2714
|
+
});
|
|
2715
|
+
this.log(LoggerLevel.debug, `[constant.metadata.fields] Constant metadata fetched: ${object_name}, code=${res.data.code}`);
|
|
2716
|
+
this.log(LoggerLevel.trace, `[constant.metadata.fields] Response: ${JSON.stringify(res.data)}`);
|
|
2717
|
+
return res.data;
|
|
2718
|
+
},
|
|
2719
|
+
/**
|
|
2720
|
+
* 获取常量对象字段详情。
|
|
2721
|
+
*/
|
|
2722
|
+
field: async (params) => {
|
|
2723
|
+
const { object_name, field_name } = params;
|
|
2724
|
+
await this.ensureTokenValid();
|
|
2725
|
+
const url = `/api/data/v1/namespaces/${this.namespace}/meta/objects/${object_name}/fields/${field_name}`;
|
|
2726
|
+
this.log(LoggerLevel.info, `[constant.metadata.field] Fetching constant field metadata: ${object_name}.${field_name}`);
|
|
2727
|
+
const res = await this.axiosInstance.get(url, {
|
|
2728
|
+
headers: this.authHeaders()
|
|
2729
|
+
});
|
|
2730
|
+
this.log(LoggerLevel.debug, `[constant.metadata.field] Constant field metadata fetched: ${object_name}.${field_name}, code=${res.data.code}`);
|
|
2731
|
+
this.log(LoggerLevel.trace, `[constant.metadata.field] Response: ${JSON.stringify(res.data)}`);
|
|
2732
|
+
return res.data;
|
|
2733
|
+
}
|
|
2734
|
+
}
|
|
2735
|
+
};
|
|
2072
2736
|
/**
|
|
2073
2737
|
* 部门 ID 交换模块
|
|
2074
2738
|
*/
|
|
@@ -2295,6 +2959,71 @@ class Client {
|
|
|
2295
2959
|
return result;
|
|
2296
2960
|
}
|
|
2297
2961
|
};
|
|
2962
|
+
/**
|
|
2963
|
+
* 集成模块
|
|
2964
|
+
*/
|
|
2965
|
+
this.integration = {
|
|
2966
|
+
lark: {
|
|
2967
|
+
/**
|
|
2968
|
+
* 获取默认飞书集成 tenantAccessToken。
|
|
2969
|
+
*/
|
|
2970
|
+
defaultTenantAccessToken: async () => {
|
|
2971
|
+
await this.ensureTokenValid();
|
|
2972
|
+
const url = `/api/integration/v1/namespaces/${this.namespace}/defaultLark/tenantAccessToken`;
|
|
2973
|
+
this.log(LoggerLevel.info, '[integration.lark.defaultTenantAccessToken] Fetching default tenant token');
|
|
2974
|
+
const res = await this.axiosInstance.get(url, {
|
|
2975
|
+
headers: this.authHeaders()
|
|
2976
|
+
});
|
|
2977
|
+
this.log(LoggerLevel.debug, `[integration.lark.defaultTenantAccessToken] Token fetched: code=${res.data.code}`);
|
|
2978
|
+
this.log(LoggerLevel.trace, `[integration.lark.defaultTenantAccessToken] Response: ${JSON.stringify(res.data)}`);
|
|
2979
|
+
return res.data;
|
|
2980
|
+
},
|
|
2981
|
+
/**
|
|
2982
|
+
* 获取默认飞书集成 appAccessToken。
|
|
2983
|
+
*/
|
|
2984
|
+
defaultAppAccessToken: async () => {
|
|
2985
|
+
await this.ensureTokenValid();
|
|
2986
|
+
const url = `/api/integration/v1/namespaces/${this.namespace}/defaultLark/appAccessToken`;
|
|
2987
|
+
this.log(LoggerLevel.info, '[integration.lark.defaultAppAccessToken] Fetching default app token');
|
|
2988
|
+
const res = await this.axiosInstance.get(url, {
|
|
2989
|
+
headers: this.authHeaders()
|
|
2990
|
+
});
|
|
2991
|
+
this.log(LoggerLevel.debug, `[integration.lark.defaultAppAccessToken] Token fetched: code=${res.data.code}`);
|
|
2992
|
+
this.log(LoggerLevel.trace, `[integration.lark.defaultAppAccessToken] Response: ${JSON.stringify(res.data)}`);
|
|
2993
|
+
return res.data;
|
|
2994
|
+
},
|
|
2995
|
+
/**
|
|
2996
|
+
* 获取自定义飞书集成 tenantAccessToken。
|
|
2997
|
+
*/
|
|
2998
|
+
tenantAccessToken: async (params) => {
|
|
2999
|
+
const { lark_integration_api_name } = params;
|
|
3000
|
+
await this.ensureTokenValid();
|
|
3001
|
+
const url = `/api/integration/v1/namespaces/${this.namespace}/lark/tenantAccessToken/${lark_integration_api_name}`;
|
|
3002
|
+
this.log(LoggerLevel.info, `[integration.lark.tenantAccessToken] Fetching tenant token: ${lark_integration_api_name}`);
|
|
3003
|
+
const res = await this.axiosInstance.get(url, {
|
|
3004
|
+
headers: this.authHeaders()
|
|
3005
|
+
});
|
|
3006
|
+
this.log(LoggerLevel.debug, `[integration.lark.tenantAccessToken] Token fetched: ${lark_integration_api_name}, code=${res.data.code}`);
|
|
3007
|
+
this.log(LoggerLevel.trace, `[integration.lark.tenantAccessToken] Response: ${JSON.stringify(res.data)}`);
|
|
3008
|
+
return res.data;
|
|
3009
|
+
},
|
|
3010
|
+
/**
|
|
3011
|
+
* 获取自定义飞书集成 appAccessToken。
|
|
3012
|
+
*/
|
|
3013
|
+
appAccessToken: async (params) => {
|
|
3014
|
+
const { lark_integration_api_name } = params;
|
|
3015
|
+
await this.ensureTokenValid();
|
|
3016
|
+
const url = `/api/integration/v1/namespaces/${this.namespace}/lark/appAccessToken/${lark_integration_api_name}`;
|
|
3017
|
+
this.log(LoggerLevel.info, `[integration.lark.appAccessToken] Fetching app token: ${lark_integration_api_name}`);
|
|
3018
|
+
const res = await this.axiosInstance.get(url, {
|
|
3019
|
+
headers: this.authHeaders()
|
|
3020
|
+
});
|
|
3021
|
+
this.log(LoggerLevel.debug, `[integration.lark.appAccessToken] Token fetched: ${lark_integration_api_name}, code=${res.data.code}`);
|
|
3022
|
+
this.log(LoggerLevel.trace, `[integration.lark.appAccessToken] Response: ${JSON.stringify(res.data)}`);
|
|
3023
|
+
return res.data;
|
|
3024
|
+
}
|
|
3025
|
+
}
|
|
3026
|
+
};
|
|
2298
3027
|
/**
|
|
2299
3028
|
* 云函数模块
|
|
2300
3029
|
*/
|
|
@@ -2748,6 +3477,59 @@ class Client {
|
|
|
2748
3477
|
}
|
|
2749
3478
|
}
|
|
2750
3479
|
};
|
|
3480
|
+
/**
|
|
3481
|
+
* 数据集模块
|
|
3482
|
+
*/
|
|
3483
|
+
this.dataset = {
|
|
3484
|
+
/**
|
|
3485
|
+
* 查询数据集列表。
|
|
3486
|
+
*/
|
|
3487
|
+
list: async (params) => {
|
|
3488
|
+
await this.ensureTokenValid();
|
|
3489
|
+
const url = `/v1/namespaces/${this.namespace}/datasets`;
|
|
3490
|
+
const requestData = params || {};
|
|
3491
|
+
this.log(LoggerLevel.info, '[dataset.list] Fetching datasets');
|
|
3492
|
+
const res = await this.axiosInstance.post(url, requestData, {
|
|
3493
|
+
headers: this.authHeaders(true)
|
|
3494
|
+
});
|
|
3495
|
+
this.log(LoggerLevel.debug, `[dataset.list] Datasets fetched: code=${res.data.code}`);
|
|
3496
|
+
this.log(LoggerLevel.trace, `[dataset.list] Response: ${JSON.stringify(res.data)}`);
|
|
3497
|
+
return res.data;
|
|
3498
|
+
},
|
|
3499
|
+
/**
|
|
3500
|
+
* 查询全部数据集 - 默认使用 cursor 分页。
|
|
3501
|
+
*/
|
|
3502
|
+
listWithIterator: async (params) => {
|
|
3503
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
3504
|
+
const pageSize = (params === null || params === void 0 ? void 0 : params.page_size) || 100;
|
|
3505
|
+
let pageToken = '';
|
|
3506
|
+
let hasMore = true;
|
|
3507
|
+
let total = 0;
|
|
3508
|
+
const datasets = [];
|
|
3509
|
+
let lastResponse = null;
|
|
3510
|
+
while (hasMore) {
|
|
3511
|
+
const res = await this.dataset.list({
|
|
3512
|
+
...params,
|
|
3513
|
+
page_type: 'cursor',
|
|
3514
|
+
page_size: pageSize,
|
|
3515
|
+
page_token: pageToken
|
|
3516
|
+
});
|
|
3517
|
+
if (res.code !== '0') {
|
|
3518
|
+
this.log(LoggerLevel.error, `[dataset.listWithIterator] Error fetching datasets: code=${res.code}, msg=${res.msg}`);
|
|
3519
|
+
throw new Error(res.msg || `Fetch failed with code ${res.code}`);
|
|
3520
|
+
}
|
|
3521
|
+
const pageDatasets = ((_a = res.data) === null || _a === void 0 ? void 0 : _a.datasets) || ((_b = res.data) === null || _b === void 0 ? void 0 : _b.items) || [];
|
|
3522
|
+
if (Array.isArray(pageDatasets)) {
|
|
3523
|
+
datasets.push(...pageDatasets);
|
|
3524
|
+
}
|
|
3525
|
+
total = (_d = (_c = res.data) === null || _c === void 0 ? void 0 : _c.total) !== null && _d !== void 0 ? _d : total;
|
|
3526
|
+
lastResponse = res;
|
|
3527
|
+
pageToken = ((_e = res.data) === null || _e === void 0 ? void 0 : _e.next_page_token) || ((_f = res.data) === null || _f === void 0 ? void 0 : _f.page_token) || '';
|
|
3528
|
+
hasMore = Boolean(((_g = res.data) === null || _g === void 0 ? void 0 : _g.has_more) && pageToken);
|
|
3529
|
+
}
|
|
3530
|
+
return { total, datasets, lastResponse };
|
|
3531
|
+
}
|
|
3532
|
+
};
|
|
2751
3533
|
/**
|
|
2752
3534
|
* 自动化流程模块
|
|
2753
3535
|
*/
|
|
@@ -2816,6 +3598,218 @@ class Client {
|
|
|
2816
3598
|
}
|
|
2817
3599
|
}
|
|
2818
3600
|
};
|
|
3601
|
+
/**
|
|
3602
|
+
* 流程模块
|
|
3603
|
+
*/
|
|
3604
|
+
this.workflow = {
|
|
3605
|
+
execution: {
|
|
3606
|
+
/**
|
|
3607
|
+
* 查询异步流程状态。
|
|
3608
|
+
*/
|
|
3609
|
+
status: async (params) => {
|
|
3610
|
+
const { execution_id } = params;
|
|
3611
|
+
await this.ensureTokenValid();
|
|
3612
|
+
const url = `/api/v2/workflow/namespaces/${this.namespace}/open_api/execution`;
|
|
3613
|
+
this.log(LoggerLevel.info, `[workflow.execution.status] Fetching execution status: ${execution_id}`);
|
|
3614
|
+
const res = await this.axiosInstance.get(url, {
|
|
3615
|
+
headers: this.authHeaders(true),
|
|
3616
|
+
params: { executionId: execution_id }
|
|
3617
|
+
});
|
|
3618
|
+
this.log(LoggerLevel.debug, `[workflow.execution.status] Execution status fetched: code=${res.data.code}`);
|
|
3619
|
+
this.log(LoggerLevel.trace, `[workflow.execution.status] Response: ${JSON.stringify(res.data)}`);
|
|
3620
|
+
return res.data;
|
|
3621
|
+
}
|
|
3622
|
+
},
|
|
3623
|
+
definition: {
|
|
3624
|
+
/**
|
|
3625
|
+
* 获取流程定义详情。
|
|
3626
|
+
*/
|
|
3627
|
+
detail: async (params) => {
|
|
3628
|
+
const { flow_api_name } = params;
|
|
3629
|
+
await this.ensureTokenValid();
|
|
3630
|
+
const url = `/api/flow/v1/namespaces/${this.namespace}/flow/${flow_api_name}`;
|
|
3631
|
+
this.log(LoggerLevel.info, `[workflow.definition.detail] Fetching flow definition: ${flow_api_name}`);
|
|
3632
|
+
const res = await this.axiosInstance.get(url, {
|
|
3633
|
+
headers: this.authHeaders()
|
|
3634
|
+
});
|
|
3635
|
+
this.log(LoggerLevel.debug, `[workflow.definition.detail] Flow definition fetched: ${flow_api_name}, code=${res.data.code}`);
|
|
3636
|
+
this.log(LoggerLevel.trace, `[workflow.definition.detail] Response: ${JSON.stringify(res.data)}`);
|
|
3637
|
+
return res.data;
|
|
3638
|
+
}
|
|
3639
|
+
},
|
|
3640
|
+
userTask: {
|
|
3641
|
+
/**
|
|
3642
|
+
* 获取包含人工任务的流程列表。
|
|
3643
|
+
*/
|
|
3644
|
+
flows: async (params) => {
|
|
3645
|
+
await this.ensureTokenValid();
|
|
3646
|
+
const url = `/api/flow/v1/namespaces/${this.namespace}/user_task/flow_list`;
|
|
3647
|
+
this.log(LoggerLevel.info, '[workflow.userTask.flows] Fetching user-task flows');
|
|
3648
|
+
const res = await this.axiosInstance.post(url, params, {
|
|
3649
|
+
headers: this.authHeaders(true)
|
|
3650
|
+
});
|
|
3651
|
+
this.log(LoggerLevel.debug, `[workflow.userTask.flows] User-task flows fetched: code=${res.data.code}`);
|
|
3652
|
+
this.log(LoggerLevel.trace, `[workflow.userTask.flows] Response: ${JSON.stringify(res.data)}`);
|
|
3653
|
+
return res.data;
|
|
3654
|
+
},
|
|
3655
|
+
/**
|
|
3656
|
+
* 获取包含人工任务的流程实例 ID 列表。
|
|
3657
|
+
*/
|
|
3658
|
+
instanceIds: async (params) => {
|
|
3659
|
+
const { page_size, page_token, start_time, end_time, api_ids } = params;
|
|
3660
|
+
await this.ensureTokenValid();
|
|
3661
|
+
const url = `/api/flow/v1/namespaces/${this.namespace}/instances/listids`;
|
|
3662
|
+
const data = {};
|
|
3663
|
+
if (start_time !== undefined)
|
|
3664
|
+
data.start_time = String(start_time);
|
|
3665
|
+
if (end_time !== undefined)
|
|
3666
|
+
data.end_time = String(end_time);
|
|
3667
|
+
if (api_ids !== undefined)
|
|
3668
|
+
data.api_ids = api_ids;
|
|
3669
|
+
this.log(LoggerLevel.info, '[workflow.userTask.instanceIds] Fetching workflow instance IDs');
|
|
3670
|
+
const res = await this.axiosInstance.get(url, {
|
|
3671
|
+
headers: this.authHeaders(true),
|
|
3672
|
+
params: { page_size, page_token },
|
|
3673
|
+
data
|
|
3674
|
+
});
|
|
3675
|
+
this.log(LoggerLevel.debug, `[workflow.userTask.instanceIds] Workflow instance IDs fetched: code=${res.data.code}`);
|
|
3676
|
+
this.log(LoggerLevel.trace, `[workflow.userTask.instanceIds] Response: ${JSON.stringify(res.data)}`);
|
|
3677
|
+
return res.data;
|
|
3678
|
+
},
|
|
3679
|
+
/**
|
|
3680
|
+
* 获取流程实例详情。
|
|
3681
|
+
*/
|
|
3682
|
+
instanceDetail: async (params) => {
|
|
3683
|
+
const { approval_instance_id, includes } = params;
|
|
3684
|
+
await this.ensureTokenValid();
|
|
3685
|
+
const url = `/api/flow/v1/namespaces/${this.namespace}/instances/${approval_instance_id}`;
|
|
3686
|
+
this.log(LoggerLevel.info, `[workflow.userTask.instanceDetail] Fetching workflow instance: ${approval_instance_id}`);
|
|
3687
|
+
const res = await this.axiosInstance.get(url, {
|
|
3688
|
+
headers: this.authHeaders(),
|
|
3689
|
+
params: includes ? { includes } : undefined
|
|
3690
|
+
});
|
|
3691
|
+
this.log(LoggerLevel.debug, `[workflow.userTask.instanceDetail] Workflow instance fetched: ${approval_instance_id}, code=${res.data.code}`);
|
|
3692
|
+
this.log(LoggerLevel.trace, `[workflow.userTask.instanceDetail] Response: ${JSON.stringify(res.data)}`);
|
|
3693
|
+
return res.data;
|
|
3694
|
+
},
|
|
3695
|
+
/**
|
|
3696
|
+
* 批量获取流程实例的任务列表。
|
|
3697
|
+
*/
|
|
3698
|
+
instanceTasks: async (params) => {
|
|
3699
|
+
const { approval_instance_ids, task_status } = params;
|
|
3700
|
+
await this.ensureTokenValid();
|
|
3701
|
+
const url = `/api/flow/v1/namespaces/${this.namespace}/instances/usertasks`;
|
|
3702
|
+
this.log(LoggerLevel.info, '[workflow.userTask.instanceTasks] Fetching workflow instance tasks');
|
|
3703
|
+
const res = await this.axiosInstance.get(url, {
|
|
3704
|
+
headers: this.authHeaders(true),
|
|
3705
|
+
params: task_status ? { task_status } : undefined,
|
|
3706
|
+
data: { approval_instance_ids }
|
|
3707
|
+
});
|
|
3708
|
+
this.log(LoggerLevel.debug, `[workflow.userTask.instanceTasks] Workflow instance tasks fetched: code=${res.data.code}`);
|
|
3709
|
+
this.log(LoggerLevel.trace, `[workflow.userTask.instanceTasks] Response: ${JSON.stringify(res.data)}`);
|
|
3710
|
+
return res.data;
|
|
3711
|
+
},
|
|
3712
|
+
/**
|
|
3713
|
+
* 获取任务列表。
|
|
3714
|
+
*/
|
|
3715
|
+
tasks: async (params) => {
|
|
3716
|
+
await this.ensureTokenValid();
|
|
3717
|
+
const url = `/api/flow/v1/namespaces/${this.namespace}/user_tasks`;
|
|
3718
|
+
this.log(LoggerLevel.info, '[workflow.userTask.tasks] Fetching user tasks');
|
|
3719
|
+
const res = await this.axiosInstance.post(url, params, {
|
|
3720
|
+
headers: this.authHeaders(true)
|
|
3721
|
+
});
|
|
3722
|
+
this.log(LoggerLevel.debug, `[workflow.userTask.tasks] User tasks fetched: code=${res.data.code}`);
|
|
3723
|
+
this.log(LoggerLevel.trace, `[workflow.userTask.tasks] Response: ${JSON.stringify(res.data)}`);
|
|
3724
|
+
return res.data;
|
|
3725
|
+
},
|
|
3726
|
+
/**
|
|
3727
|
+
* 获取任务详情。
|
|
3728
|
+
*/
|
|
3729
|
+
detail: async (params) => {
|
|
3730
|
+
const { task_id } = params;
|
|
3731
|
+
await this.ensureTokenValid();
|
|
3732
|
+
const url = `/api/flow/v1/namespaces/${this.namespace}/user_task/${task_id}/detail`;
|
|
3733
|
+
this.log(LoggerLevel.info, `[workflow.userTask.detail] Fetching user task: ${task_id}`);
|
|
3734
|
+
const res = await this.axiosInstance.get(url, {
|
|
3735
|
+
headers: this.authHeaders()
|
|
3736
|
+
});
|
|
3737
|
+
this.log(LoggerLevel.debug, `[workflow.userTask.detail] User task fetched: ${task_id}, code=${res.data.code}`);
|
|
3738
|
+
this.log(LoggerLevel.trace, `[workflow.userTask.detail] Response: ${JSON.stringify(res.data)}`);
|
|
3739
|
+
return res.data;
|
|
3740
|
+
},
|
|
3741
|
+
agree: async (params) => {
|
|
3742
|
+
const { approval_task_id, ...data } = params;
|
|
3743
|
+
await this.ensureTokenValid();
|
|
3744
|
+
const url = `/api/flow/v1/namespaces/${this.namespace}/user_task/${approval_task_id}/agree`;
|
|
3745
|
+
const res = await this.axiosInstance.post(url, data, { headers: this.authHeaders(true) });
|
|
3746
|
+
return res.data;
|
|
3747
|
+
},
|
|
3748
|
+
reject: async (params) => {
|
|
3749
|
+
const { approval_task_id, ...data } = params;
|
|
3750
|
+
await this.ensureTokenValid();
|
|
3751
|
+
const url = `/api/flow/v1/namespaces/${this.namespace}/user_task/${approval_task_id}/reject`;
|
|
3752
|
+
const res = await this.axiosInstance.post(url, data, { headers: this.authHeaders(true) });
|
|
3753
|
+
return res.data;
|
|
3754
|
+
},
|
|
3755
|
+
transfer: async (params) => {
|
|
3756
|
+
const { approval_task_id, ...data } = params;
|
|
3757
|
+
await this.ensureTokenValid();
|
|
3758
|
+
const url = `/api/flow/v1/namespaces/${this.namespace}/user_task/${approval_task_id}/trans`;
|
|
3759
|
+
const res = await this.axiosInstance.post(url, data, { headers: this.authHeaders(true) });
|
|
3760
|
+
return res.data;
|
|
3761
|
+
},
|
|
3762
|
+
addAssignee: async (params) => {
|
|
3763
|
+
const { approval_task_id, ...data } = params;
|
|
3764
|
+
await this.ensureTokenValid();
|
|
3765
|
+
const url = `/api/flow/v1/namespaces/${this.namespace}/user_task/${approval_task_id}/add_assignee`;
|
|
3766
|
+
const res = await this.axiosInstance.post(url, data, { headers: this.authHeaders(true) });
|
|
3767
|
+
return res.data;
|
|
3768
|
+
},
|
|
3769
|
+
cc: async (params) => {
|
|
3770
|
+
const { task_id, ...data } = params;
|
|
3771
|
+
await this.ensureTokenValid();
|
|
3772
|
+
const url = `/api/flow/v1/namespaces/${this.namespace}/user_task/${task_id}/cc`;
|
|
3773
|
+
const res = await this.axiosInstance.post(url, data, { headers: this.authHeaders(true) });
|
|
3774
|
+
return res.data;
|
|
3775
|
+
},
|
|
3776
|
+
expedite: async (params) => {
|
|
3777
|
+
const { task_id, ...data } = params;
|
|
3778
|
+
await this.ensureTokenValid();
|
|
3779
|
+
const url = `/api/flow/v1/namespaces/${this.namespace}/user_task/${task_id}/expediting`;
|
|
3780
|
+
const res = await this.axiosInstance.post(url, data, { headers: this.authHeaders(true) });
|
|
3781
|
+
return res.data;
|
|
3782
|
+
},
|
|
3783
|
+
cancelInstance: async (params) => {
|
|
3784
|
+
const { approval_instance_id, ...data } = params;
|
|
3785
|
+
await this.ensureTokenValid();
|
|
3786
|
+
const url = `/api/flow/v1/namespaces/${this.namespace}/instance/${approval_instance_id}/cancel`;
|
|
3787
|
+
const res = await this.axiosInstance.post(url, data, { headers: this.authHeaders(true) });
|
|
3788
|
+
return res.data;
|
|
3789
|
+
},
|
|
3790
|
+
rollbackPoints: async (params) => {
|
|
3791
|
+
const { task_id, ...data } = params;
|
|
3792
|
+
await this.ensureTokenValid();
|
|
3793
|
+
const url = `/api/flow/v1/namespaces/${this.namespace}/user_task/${task_id}/rollback_points`;
|
|
3794
|
+
const res = await this.axiosInstance.post(url, data, { headers: this.authHeaders(true) });
|
|
3795
|
+
return res.data;
|
|
3796
|
+
},
|
|
3797
|
+
rollback: async (params) => {
|
|
3798
|
+
const { task_id, ...data } = params;
|
|
3799
|
+
await this.ensureTokenValid();
|
|
3800
|
+
const url = `/api/flow/v1/namespaces/${this.namespace}/user_task/${task_id}/rollback`;
|
|
3801
|
+
const res = await this.axiosInstance.post(url, data, { headers: this.authHeaders(true) });
|
|
3802
|
+
return res.data;
|
|
3803
|
+
},
|
|
3804
|
+
startChat: async (params) => {
|
|
3805
|
+
const { task_id, ...data } = params;
|
|
3806
|
+
await this.ensureTokenValid();
|
|
3807
|
+
const url = `/api/flow/v1/namespaces/${this.namespace}/user_task/${task_id}/chat`;
|
|
3808
|
+
const res = await this.axiosInstance.post(url, data, { headers: this.authHeaders(true) });
|
|
3809
|
+
return res.data;
|
|
3810
|
+
}
|
|
3811
|
+
}
|
|
3812
|
+
};
|
|
2819
3813
|
/**
|
|
2820
3814
|
* 数据对象结构管理模块(Schema)
|
|
2821
3815
|
*/
|
|
@@ -2828,12 +3822,13 @@ class Client {
|
|
|
2828
3822
|
*/
|
|
2829
3823
|
create: async (params) => {
|
|
2830
3824
|
const { objects } = params;
|
|
3825
|
+
const requestObjects = normalizeSchemaObjectsForWrite(objects);
|
|
2831
3826
|
await this.ensureTokenValid();
|
|
2832
3827
|
const url = `/v1/namespaces/${this.namespace}/objects/batch_create`;
|
|
2833
3828
|
this.log(LoggerLevel.info, `[schema.create] Creating ${objects.length} object(s)`);
|
|
2834
3829
|
this.log(LoggerLevel.trace, `[schema.create] Request URL: ${this.axiosInstance.defaults.baseURL}${url}`);
|
|
2835
|
-
this.log(LoggerLevel.trace, `[schema.create] Request Body: ${JSON.stringify({ objects }, null, 2)}`);
|
|
2836
|
-
const res = await this.axiosInstance.post(url, { objects }, {
|
|
3830
|
+
this.log(LoggerLevel.trace, `[schema.create] Request Body: ${JSON.stringify({ objects: requestObjects }, null, 2)}`);
|
|
3831
|
+
const res = await this.axiosInstance.post(url, { objects: requestObjects }, {
|
|
2837
3832
|
headers: {
|
|
2838
3833
|
Authorization: `${this.accessToken}`,
|
|
2839
3834
|
'Content-Type': 'application/json'
|
|
@@ -2890,12 +3885,13 @@ class Client {
|
|
|
2890
3885
|
*/
|
|
2891
3886
|
update: async (params) => {
|
|
2892
3887
|
const { objects } = params;
|
|
3888
|
+
const requestObjects = normalizeSchemaObjectsForWrite(objects);
|
|
2893
3889
|
await this.ensureTokenValid();
|
|
2894
3890
|
const url = `/v1/namespaces/${this.namespace}/objects/batch_update`;
|
|
2895
3891
|
this.log(LoggerLevel.info, `[schema.update] Updating ${objects.length} object(s)`);
|
|
2896
3892
|
this.log(LoggerLevel.trace, `[schema.update] Request URL: ${this.axiosInstance.defaults.baseURL}${url}`);
|
|
2897
|
-
this.log(LoggerLevel.trace, `[schema.update] Request Body: ${JSON.stringify({ objects }, null, 2)}`);
|
|
2898
|
-
const res = await this.axiosInstance.post(url, { objects }, {
|
|
3893
|
+
this.log(LoggerLevel.trace, `[schema.update] Request Body: ${JSON.stringify({ objects: requestObjects }, null, 2)}`);
|
|
3894
|
+
const res = await this.axiosInstance.post(url, { objects: requestObjects }, {
|
|
2899
3895
|
headers: {
|
|
2900
3896
|
Authorization: `${this.accessToken}`,
|
|
2901
3897
|
'Content-Type': 'application/json'
|
|
@@ -2939,6 +3935,48 @@ class Client {
|
|
|
2939
3935
|
this.log(LoggerLevel.debug, `[schema.delete] Objects deleted: code=${res.data.code}`);
|
|
2940
3936
|
this.log(LoggerLevel.trace, `[schema.delete] Response: ${JSON.stringify(res.data)}`);
|
|
2941
3937
|
return res.data;
|
|
3938
|
+
},
|
|
3939
|
+
/**
|
|
3940
|
+
* 校验 schema 写接口响应,覆盖请求级错误、data=null 静默失败、item 级失败。
|
|
3941
|
+
*/
|
|
3942
|
+
checkResponse: checkSchemaResponse,
|
|
3943
|
+
/**
|
|
3944
|
+
* 返回 schema 写接口响应校验结果,不抛错。
|
|
3945
|
+
*/
|
|
3946
|
+
validateResponse: validateSchemaResponse,
|
|
3947
|
+
/**
|
|
3948
|
+
* 按 schema 单批 10 个对象的限制分批执行。
|
|
3949
|
+
*/
|
|
3950
|
+
batchExecute,
|
|
3951
|
+
/**
|
|
3952
|
+
* 创建对象空壳。会移除 fields,并将 display/search 临时指向 _id。
|
|
3953
|
+
*/
|
|
3954
|
+
createShells: async (params) => {
|
|
3955
|
+
return createSchemaObjectShells(this, params.objects, params);
|
|
3956
|
+
},
|
|
3957
|
+
/**
|
|
3958
|
+
* 幂等添加字段:先读 metadata,跳过已存在字段,再调用 schema.update。
|
|
3959
|
+
*/
|
|
3960
|
+
addFieldsIdempotent: async (params) => {
|
|
3961
|
+
return addFieldsIdempotent(this, params.object_name, params.fields, params);
|
|
3962
|
+
},
|
|
3963
|
+
/**
|
|
3964
|
+
* 三阶段创建对象:空壳 -> 基础字段 -> lookup -> reference_field -> final settings。
|
|
3965
|
+
*/
|
|
3966
|
+
createWithStages: async (params) => {
|
|
3967
|
+
return createSchemaObjectsInStages(this, params.objects, params);
|
|
3968
|
+
},
|
|
3969
|
+
/**
|
|
3970
|
+
* 写后验证对象和字段,可选导出 Markdown。
|
|
3971
|
+
*/
|
|
3972
|
+
verifyObjects: async (params) => {
|
|
3973
|
+
return verifySchemaObjects(this, params.object_names, params);
|
|
3974
|
+
},
|
|
3975
|
+
/**
|
|
3976
|
+
* 删除全部自定义对象。高风险操作,必须显式传 confirm: true。
|
|
3977
|
+
*/
|
|
3978
|
+
deleteAllCustomObjects: async (params) => {
|
|
3979
|
+
return deleteAllCustomObjects(this, params);
|
|
2942
3980
|
}
|
|
2943
3981
|
};
|
|
2944
3982
|
this.clientId = options.clientId;
|
|
@@ -3048,31 +4086,56 @@ class Client {
|
|
|
3048
4086
|
this.log(LoggerLevel.debug, `[namespace] Current namespace: ${this.namespace}`);
|
|
3049
4087
|
return this.namespace;
|
|
3050
4088
|
}
|
|
4089
|
+
authHeaders(includeContentType = false) {
|
|
4090
|
+
return includeContentType
|
|
4091
|
+
? { Authorization: `${this.accessToken}`, 'Content-Type': 'application/json' }
|
|
4092
|
+
: { Authorization: `${this.accessToken}` };
|
|
4093
|
+
}
|
|
3051
4094
|
}
|
|
3052
4095
|
const apaas = {
|
|
3053
4096
|
Client
|
|
3054
4097
|
};
|
|
3055
4098
|
|
|
3056
4099
|
exports.BATCH_UPDATE_REQUIREMENTS = BATCH_UPDATE_REQUIREMENTS;
|
|
4100
|
+
exports.COLUMN_NAME_SEMANTIC_RULES = COLUMN_NAME_SEMANTIC_RULES;
|
|
3057
4101
|
exports.CREATE_OBJECT_EXAMPLE = CREATE_OBJECT_EXAMPLE;
|
|
3058
4102
|
exports.FIELD_SCHEMA_RULES = FIELD_SCHEMA_RULES;
|
|
3059
4103
|
exports.FIELD_TYPES = FIELD_TYPES;
|
|
3060
4104
|
exports.LANGUAGE_CODES = LANGUAGE_CODES;
|
|
4105
|
+
exports.OPTION_COLOR_CODE_BY_NAME = OPTION_COLOR_CODE_BY_NAME;
|
|
3061
4106
|
exports.OPTION_COLOR_LIST = OPTION_COLOR_LIST;
|
|
4107
|
+
exports.OPTION_COLOR_NAME_BY_CODE = OPTION_COLOR_NAME_BY_CODE;
|
|
3062
4108
|
exports.OPTION_COLOR_RULES = OPTION_COLOR_RULES;
|
|
4109
|
+
exports.SCHEMA_BATCH_SIZE = SCHEMA_BATCH_SIZE;
|
|
3063
4110
|
exports.SCHEMA_GUIDELINES = SCHEMA_GUIDELINES;
|
|
3064
4111
|
exports.SCHEMA_TYPE_BY_METADATA_TYPE = SCHEMA_TYPE_BY_METADATA_TYPE;
|
|
3065
4112
|
exports.SCHEMA_TYPE_MISMATCHES = SCHEMA_TYPE_MISMATCHES;
|
|
4113
|
+
exports.SQL_CONSTRAINT_TO_SETTINGS = SQL_CONSTRAINT_TO_SETTINGS;
|
|
4114
|
+
exports.SQL_TYPE_TO_SCHEMA_TYPE = SQL_TYPE_TO_SCHEMA_TYPE;
|
|
3066
4115
|
exports.SYSTEM_FIELDS = SYSTEM_FIELDS;
|
|
3067
4116
|
exports.UPDATE_OBJECT_ADD_FIELD_EXAMPLE = UPDATE_OBJECT_ADD_FIELD_EXAMPLE;
|
|
3068
4117
|
exports.UPDATE_OBJECT_REMOVE_FIELD_EXAMPLE = UPDATE_OBJECT_REMOVE_FIELD_EXAMPLE;
|
|
3069
4118
|
exports.UPDATE_OBJECT_REPLACE_FIELD_EXAMPLE = UPDATE_OBJECT_REPLACE_FIELD_EXAMPLE;
|
|
3070
4119
|
exports.UPDATE_OBJECT_SETTINGS_EXAMPLE = UPDATE_OBJECT_SETTINGS_EXAMPLE;
|
|
4120
|
+
exports.addFieldsIdempotent = addFieldsIdempotent;
|
|
3071
4121
|
exports.apaas = apaas;
|
|
4122
|
+
exports.batchExecute = batchExecute;
|
|
4123
|
+
exports.buildFieldRemovalPlan = buildFieldRemovalPlan;
|
|
4124
|
+
exports.checkSchemaResponse = checkSchemaResponse;
|
|
3072
4125
|
exports.createMultilingualText = createMultilingualText;
|
|
4126
|
+
exports.createSchemaObjectShells = createSchemaObjectShells;
|
|
4127
|
+
exports.createSchemaObjectsInStages = createSchemaObjectsInStages;
|
|
4128
|
+
exports.deleteAllCustomObjects = deleteAllCustomObjects;
|
|
3073
4129
|
exports.extractMultilingualText = extractMultilingualText;
|
|
3074
4130
|
exports.getCustomFieldTypes = getCustomFieldTypes;
|
|
3075
4131
|
exports.getFieldType = getFieldType;
|
|
3076
4132
|
exports.getOptionColor = getOptionColor;
|
|
4133
|
+
exports.getOptionColorCode = getOptionColorCode;
|
|
3077
4134
|
exports.getSystemFields = getSystemFields;
|
|
3078
4135
|
exports.isSystemField = isSystemField;
|
|
4136
|
+
exports.isSystemSchemaName = isSystemSchemaName;
|
|
4137
|
+
exports.normalizeOptionColorForSchema = normalizeOptionColorForSchema;
|
|
4138
|
+
exports.normalizeSchemaObjectsForWrite = normalizeSchemaObjectsForWrite;
|
|
4139
|
+
exports.splitSchemaFieldsByDependency = splitSchemaFieldsByDependency;
|
|
4140
|
+
exports.validateSchemaResponse = validateSchemaResponse;
|
|
4141
|
+
exports.verifySchemaObjects = verifySchemaObjects;
|