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
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import type { CreateFieldDefinition, MultilingualText, ObjectSettings, UpdateFieldDefinition } from './field-types';
|
|
2
|
+
export declare const SCHEMA_BATCH_SIZE = 10;
|
|
3
|
+
export type SchemaResponseFailureLayer = 'request' | 'silent' | 'item';
|
|
4
|
+
export interface SchemaResponseItem {
|
|
5
|
+
api_name?: string;
|
|
6
|
+
apiName?: string;
|
|
7
|
+
name?: string;
|
|
8
|
+
status?: {
|
|
9
|
+
code?: string | number;
|
|
10
|
+
message?: string;
|
|
11
|
+
msg?: string;
|
|
12
|
+
};
|
|
13
|
+
[key: string]: any;
|
|
14
|
+
}
|
|
15
|
+
export interface SchemaResponse {
|
|
16
|
+
code?: string | number;
|
|
17
|
+
msg?: string;
|
|
18
|
+
message?: string;
|
|
19
|
+
data?: {
|
|
20
|
+
items?: SchemaResponseItem[];
|
|
21
|
+
[key: string]: any;
|
|
22
|
+
} | null;
|
|
23
|
+
[key: string]: any;
|
|
24
|
+
}
|
|
25
|
+
export interface SchemaResponseFailure {
|
|
26
|
+
layer: SchemaResponseFailureLayer;
|
|
27
|
+
context: string;
|
|
28
|
+
code?: string;
|
|
29
|
+
message: string;
|
|
30
|
+
apiName?: string;
|
|
31
|
+
item?: SchemaResponseItem;
|
|
32
|
+
}
|
|
33
|
+
export interface SchemaResponseValidationOptions {
|
|
34
|
+
requireItemStatus?: boolean;
|
|
35
|
+
allowDataNull?: boolean;
|
|
36
|
+
}
|
|
37
|
+
export interface SchemaResponseValidationResult<T extends SchemaResponse = SchemaResponse> {
|
|
38
|
+
ok: boolean;
|
|
39
|
+
result: T;
|
|
40
|
+
failures: SchemaResponseFailure[];
|
|
41
|
+
}
|
|
42
|
+
export interface SchemaBatchInfo {
|
|
43
|
+
batchIndex: number;
|
|
44
|
+
batchCount: number;
|
|
45
|
+
start: number;
|
|
46
|
+
end: number;
|
|
47
|
+
batchSize: number;
|
|
48
|
+
}
|
|
49
|
+
export interface SchemaBatchExecuteOptions {
|
|
50
|
+
batchSize?: number;
|
|
51
|
+
context?: string;
|
|
52
|
+
continueOnError?: boolean;
|
|
53
|
+
checkResponse?: boolean;
|
|
54
|
+
responseOptions?: SchemaResponseValidationOptions;
|
|
55
|
+
}
|
|
56
|
+
export interface SchemaBatchExecuteResult<R extends SchemaResponse = SchemaResponse> {
|
|
57
|
+
ok: boolean;
|
|
58
|
+
total: number;
|
|
59
|
+
batchSize: number;
|
|
60
|
+
batchCount: number;
|
|
61
|
+
results: R[];
|
|
62
|
+
failures: SchemaResponseFailure[];
|
|
63
|
+
}
|
|
64
|
+
export type SchemaStageFieldDefinition = (CreateFieldDefinition | UpdateFieldDefinition) & {
|
|
65
|
+
operator?: 'add' | 'replace' | 'remove';
|
|
66
|
+
};
|
|
67
|
+
export interface SchemaManagedObjectDefinition {
|
|
68
|
+
api_name: string;
|
|
69
|
+
label: MultilingualText;
|
|
70
|
+
settings?: ObjectSettings;
|
|
71
|
+
fields?: SchemaStageFieldDefinition[];
|
|
72
|
+
[key: string]: any;
|
|
73
|
+
}
|
|
74
|
+
export interface SchemaCreateShellsOptions extends SchemaBatchExecuteOptions {
|
|
75
|
+
skipExisting?: boolean;
|
|
76
|
+
}
|
|
77
|
+
export interface SchemaAddFieldsOptions {
|
|
78
|
+
context?: string;
|
|
79
|
+
skipExisting?: boolean;
|
|
80
|
+
checkResponse?: boolean;
|
|
81
|
+
responseOptions?: SchemaResponseValidationOptions;
|
|
82
|
+
}
|
|
83
|
+
export interface SchemaAddFieldsResult {
|
|
84
|
+
objectName: string;
|
|
85
|
+
addedFields: string[];
|
|
86
|
+
skippedFields: string[];
|
|
87
|
+
result?: SchemaResponse;
|
|
88
|
+
}
|
|
89
|
+
export interface SchemaCreateShellsResult {
|
|
90
|
+
requested: string[];
|
|
91
|
+
created: string[];
|
|
92
|
+
skippedExisting: string[];
|
|
93
|
+
batches?: SchemaBatchExecuteResult;
|
|
94
|
+
}
|
|
95
|
+
export interface SchemaCreateObjectsInStagesOptions extends SchemaBatchExecuteOptions {
|
|
96
|
+
skipExisting?: boolean;
|
|
97
|
+
updateFinalSettings?: boolean;
|
|
98
|
+
verify?: boolean;
|
|
99
|
+
includeMarkdown?: boolean;
|
|
100
|
+
}
|
|
101
|
+
export interface SchemaCreateObjectsInStagesResult {
|
|
102
|
+
shells: SchemaCreateShellsResult;
|
|
103
|
+
baseFields: SchemaAddFieldsResult[];
|
|
104
|
+
lookupFields: SchemaAddFieldsResult[];
|
|
105
|
+
referenceFields: SchemaAddFieldsResult[];
|
|
106
|
+
finalSettings?: SchemaBatchExecuteResult;
|
|
107
|
+
verification?: SchemaVerificationResult;
|
|
108
|
+
}
|
|
109
|
+
export interface SchemaObjectVerification {
|
|
110
|
+
objectName: string;
|
|
111
|
+
exists: boolean;
|
|
112
|
+
fields: any[];
|
|
113
|
+
customFields: any[];
|
|
114
|
+
}
|
|
115
|
+
export interface SchemaVerificationResult {
|
|
116
|
+
objects: SchemaObjectVerification[];
|
|
117
|
+
markdown?: string;
|
|
118
|
+
}
|
|
119
|
+
export interface SchemaVerificationOptions {
|
|
120
|
+
includeMarkdown?: boolean;
|
|
121
|
+
}
|
|
122
|
+
export interface SchemaFieldRemovalPlan {
|
|
123
|
+
referenceFieldObjects: Array<{
|
|
124
|
+
api_name: string;
|
|
125
|
+
fields: Array<{
|
|
126
|
+
operator: 'remove';
|
|
127
|
+
api_name: string;
|
|
128
|
+
}>;
|
|
129
|
+
}>;
|
|
130
|
+
lookupObjects: Array<{
|
|
131
|
+
api_name: string;
|
|
132
|
+
fields: Array<{
|
|
133
|
+
operator: 'remove';
|
|
134
|
+
api_name: string;
|
|
135
|
+
}>;
|
|
136
|
+
}>;
|
|
137
|
+
otherFieldObjects: Array<{
|
|
138
|
+
api_name: string;
|
|
139
|
+
fields: Array<{
|
|
140
|
+
operator: 'remove';
|
|
141
|
+
api_name: string;
|
|
142
|
+
}>;
|
|
143
|
+
}>;
|
|
144
|
+
}
|
|
145
|
+
export interface DeleteAllCustomObjectsOptions extends SchemaBatchExecuteOptions {
|
|
146
|
+
confirm?: boolean;
|
|
147
|
+
removeOtherFields?: boolean;
|
|
148
|
+
verify?: boolean;
|
|
149
|
+
}
|
|
150
|
+
export interface DeleteAllCustomObjectsResult {
|
|
151
|
+
deletedObjects: string[];
|
|
152
|
+
removalPlan: SchemaFieldRemovalPlan;
|
|
153
|
+
fieldRemovalResults: SchemaBatchExecuteResult[];
|
|
154
|
+
deleteResults?: SchemaBatchExecuteResult;
|
|
155
|
+
remainingObjects?: string[];
|
|
156
|
+
}
|
|
157
|
+
export interface SchemaClientLike {
|
|
158
|
+
schema: {
|
|
159
|
+
create(params: any): Promise<SchemaResponse>;
|
|
160
|
+
update(params: any): Promise<SchemaResponse>;
|
|
161
|
+
delete(params: any): Promise<SchemaResponse>;
|
|
162
|
+
};
|
|
163
|
+
object: {
|
|
164
|
+
listWithIterator(params?: any): Promise<{
|
|
165
|
+
items?: any[];
|
|
166
|
+
}>;
|
|
167
|
+
metadata: {
|
|
168
|
+
fields(params: {
|
|
169
|
+
object_name: string;
|
|
170
|
+
}): Promise<any>;
|
|
171
|
+
export2markdown?(options?: {
|
|
172
|
+
object_names?: string[];
|
|
173
|
+
}): Promise<string>;
|
|
174
|
+
};
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
export declare function isSystemSchemaName(apiName: string): boolean;
|
|
178
|
+
export declare function normalizeSchemaObjectsForWrite<T extends {
|
|
179
|
+
fields?: any[];
|
|
180
|
+
}>(objects: T[]): T[];
|
|
181
|
+
export declare function validateSchemaResponse<T extends SchemaResponse>(result: T, context?: string, options?: SchemaResponseValidationOptions): SchemaResponseValidationResult<T>;
|
|
182
|
+
export declare function checkSchemaResponse<T extends SchemaResponse>(result: T, context?: string, options?: SchemaResponseValidationOptions): T;
|
|
183
|
+
export declare function batchExecute<T, R extends SchemaResponse>(items: T[], fn: (batch: T[], info: SchemaBatchInfo) => Promise<R>, options?: SchemaBatchExecuteOptions): Promise<SchemaBatchExecuteResult<R>>;
|
|
184
|
+
export declare function splitSchemaFieldsByDependency(fields: SchemaStageFieldDefinition[]): {
|
|
185
|
+
baseFields: SchemaStageFieldDefinition[];
|
|
186
|
+
lookupFields: SchemaStageFieldDefinition[];
|
|
187
|
+
referenceFields: SchemaStageFieldDefinition[];
|
|
188
|
+
};
|
|
189
|
+
export declare function createSchemaObjectShells(client: SchemaClientLike, objects: SchemaManagedObjectDefinition[], options?: SchemaCreateShellsOptions): Promise<SchemaCreateShellsResult>;
|
|
190
|
+
export declare function addFieldsIdempotent(client: SchemaClientLike, objectName: string, fieldsToAdd: SchemaStageFieldDefinition[], options?: SchemaAddFieldsOptions): Promise<SchemaAddFieldsResult>;
|
|
191
|
+
export declare function createSchemaObjectsInStages(client: SchemaClientLike, objects: SchemaManagedObjectDefinition[], options?: SchemaCreateObjectsInStagesOptions): Promise<SchemaCreateObjectsInStagesResult>;
|
|
192
|
+
export declare function verifySchemaObjects(client: SchemaClientLike, objectNames: string[], options?: SchemaVerificationOptions): Promise<SchemaVerificationResult>;
|
|
193
|
+
export declare function buildFieldRemovalPlan(fieldsByObject: Record<string, any[]>): SchemaFieldRemovalPlan;
|
|
194
|
+
export declare function deleteAllCustomObjects(client: SchemaClientLike, options?: DeleteAllCustomObjectsOptions): Promise<DeleteAllCustomObjectsResult>;
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "apaas-oapi-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"bin": {
|
|
6
|
-
"apaas-oapi-client": "
|
|
6
|
+
"apaas-oapi-client": "bin/apaas-oapi-client.js"
|
|
7
7
|
},
|
|
8
8
|
"exports": {
|
|
9
9
|
".": "./dist/index.js",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"author": "",
|
|
29
29
|
"repository": {
|
|
30
30
|
"type": "git",
|
|
31
|
-
"url": "https://github.com/ennann/apaas-oapi-node-client"
|
|
31
|
+
"url": "git+https://github.com/ennann/apaas-oapi-node-client.git"
|
|
32
32
|
},
|
|
33
33
|
"license": "ISC",
|
|
34
34
|
"dependencies": {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: apaas-function-flow
|
|
3
|
-
description: "Use for aPaaS Node SDK cloud function
|
|
3
|
+
description: "Use for aPaaS Node SDK cloud function, automation flow, workflow, user task, and Lark integration token operations: invoking functions, executing v1/v2 flows, querying execution status, task approve/reject/transfer/rollback/chat, checking code/msg/data, and avoiding unsafe repeated workflow submissions."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# aPaaS Function Flow
|
|
7
7
|
|
|
8
|
-
Use this skill for `client.function
|
|
8
|
+
Use this skill for `client.function.*`, `client.automation.*`, `client.workflow.*`, and `client.integration.lark.*`.
|
|
9
9
|
|
|
10
10
|
## Function Invoke
|
|
11
11
|
|
|
@@ -42,9 +42,54 @@ const res = await client.automation.v2.execute({
|
|
|
42
42
|
});
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
+
## Workflow Status And Definition
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
const status = await client.workflow.execution.status({
|
|
49
|
+
execution_id: "1848390852196499"
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const flow = await client.workflow.definition.detail({
|
|
53
|
+
flow_api_name: "package_xxx__c__action_xxx"
|
|
54
|
+
});
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## User Tasks
|
|
58
|
+
|
|
59
|
+
Use `client.workflow.userTask.*` for human task workflows. Treat approve/reject/transfer/rollback/cancel as writes.
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
const tasks = await client.workflow.userTask.tasks({
|
|
63
|
+
type: "pending",
|
|
64
|
+
source: "assignMe",
|
|
65
|
+
kunlun_user_id: "1783981209205788",
|
|
66
|
+
limit: 20,
|
|
67
|
+
offset: 0
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
await client.workflow.userTask.agree({
|
|
71
|
+
approval_task_id: "1785996265147395",
|
|
72
|
+
user_id: "1783981209205788",
|
|
73
|
+
opinion: "同意"
|
|
74
|
+
});
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Lark Integration Tokens
|
|
78
|
+
|
|
79
|
+
Use this only when the user needs to call Lark OpenAPI through a configured aPaaS integration.
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
const token = await client.integration.lark.defaultTenantAccessToken();
|
|
83
|
+
|
|
84
|
+
const customToken = await client.integration.lark.appAccessToken({
|
|
85
|
+
lark_integration_api_name: "larkIntegration_xxx"
|
|
86
|
+
});
|
|
87
|
+
```
|
|
88
|
+
|
|
45
89
|
## Safety
|
|
46
90
|
|
|
47
91
|
- Treat flow execution as a write operation; confirm before triggering production workflows.
|
|
92
|
+
- Treat user task actions and workflow instance cancel/rollback as write operations.
|
|
48
93
|
- Do not resubmit failed flows with `is_resubmit` unless the user explicitly requests it and `pre_instance_id` is known.
|
|
49
94
|
- Log flow/function names and result codes, not secrets or full sensitive payloads.
|
|
50
95
|
- If the flow mutates records, verify the target record after execution with `apaas-object`.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
interface:
|
|
2
2
|
display_name: "aPaaS Function Flow"
|
|
3
|
-
short_description: "aPaaS
|
|
4
|
-
default_prompt: "Use $apaas-function-flow to invoke
|
|
3
|
+
short_description: "aPaaS 云函数、自动化流程、工作流人工任务与飞书集成 token 指南"
|
|
4
|
+
default_prompt: "Use $apaas-function-flow to invoke functions, execute flows, handle workflow user tasks, or fetch Lark integration tokens."
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: apaas-object
|
|
3
|
-
description: "Use for aPaaS Node SDK object
|
|
3
|
+
description: "Use for aPaaS Node SDK object/data operations: object metadata, fields, Markdown export, record CRUD, batch operations, OQL, cross-object search, constant objects, datasets, pagination, ID cursor pagination, and record-level error recovery."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# aPaaS Object
|
|
7
7
|
|
|
8
|
-
Use this skill for `client.object.*`.
|
|
8
|
+
Use this skill for `client.object.*`, `client.constant.*`, and `client.dataset.*`.
|
|
9
9
|
|
|
10
10
|
## Workflow
|
|
11
11
|
|
|
@@ -15,6 +15,8 @@ Use this skill for `client.object.*`.
|
|
|
15
15
|
4. Use iterator helpers for full-result work.
|
|
16
16
|
5. Check SDK response codes and failed item lists.
|
|
17
17
|
|
|
18
|
+
Read [references/id-cursor-pagination.md](references/id-cursor-pagination.md) when a task needs full-table reads, large offset pagination, or a doc mentions ID cursor pagination.
|
|
19
|
+
|
|
18
20
|
## Metadata
|
|
19
21
|
|
|
20
22
|
Prefer metadata calls before record work:
|
|
@@ -42,6 +44,8 @@ Use returned API names, not user-facing labels, in later calls.
|
|
|
42
44
|
- Use `search.records` for one page.
|
|
43
45
|
- Use `search.recordsWithIterator` for full-table or full-filter tasks.
|
|
44
46
|
- Use `search.count` when only the count is needed.
|
|
47
|
+
- Use `object.oql` when the user gives an OQL statement or needs OQL-only query features.
|
|
48
|
+
- Use `search.recordsAcrossObjects` for global search across up to 5 objects.
|
|
45
49
|
|
|
46
50
|
```ts
|
|
47
51
|
const { total, items } = await client.object.search.recordsWithIterator({
|
|
@@ -58,6 +62,41 @@ const { total, items } = await client.object.search.recordsWithIterator({
|
|
|
58
62
|
|
|
59
63
|
Do not answer global max/min/top/count questions from a single page unless the user asked for a sample.
|
|
60
64
|
|
|
65
|
+
## OQL And Cross-Object Search
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
const oql = await client.object.oql({
|
|
69
|
+
query: "SELECT _id, _name FROM _user WHERE _type = $1 LIMIT 10",
|
|
70
|
+
args: ["_employee"]
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const search = await client.object.search.recordsAcrossObjects({
|
|
74
|
+
q: "Ethan",
|
|
75
|
+
search_objects: [{
|
|
76
|
+
api_name: "_user",
|
|
77
|
+
select: ["_id", "_name"],
|
|
78
|
+
search_fields: ["_name"]
|
|
79
|
+
}],
|
|
80
|
+
page_size: 20,
|
|
81
|
+
metadata: "Label"
|
|
82
|
+
});
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Constant Objects And Datasets
|
|
86
|
+
|
|
87
|
+
Use `client.constant.*` for `_currency`, `_country`, and `_timeZone`.
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
const currencies = await client.constant.records({
|
|
91
|
+
object_name: "_currency",
|
|
92
|
+
data: { limit: 100, offset: 0, count: false, fields: ["_id", "_name"] }
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const datasets = await client.dataset.listWithIterator({
|
|
96
|
+
page_size: 100
|
|
97
|
+
});
|
|
98
|
+
```
|
|
99
|
+
|
|
61
100
|
## Record Writes
|
|
62
101
|
|
|
63
102
|
Use storage fields only. Re-read metadata when unsure.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
interface:
|
|
2
2
|
display_name: "aPaaS Object"
|
|
3
|
-
short_description: "aPaaS
|
|
4
|
-
default_prompt: "Use $apaas-object to read metadata and operate records
|
|
3
|
+
short_description: "aPaaS 对象元数据、记录读写、OQL、跨对象搜索、常量对象与数据集指南"
|
|
4
|
+
default_prompt: "Use $apaas-object to read metadata and operate aPaaS records, constants, datasets, OQL, or cross-object search."
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# ID Cursor Pagination
|
|
2
|
+
|
|
3
|
+
Use this when an endpoint exposes `limit`/`offset` but does not provide a reliable `page_token`. Large offset queries can become slow and are more likely to hit rate limits.
|
|
4
|
+
|
|
5
|
+
## Preferred Order
|
|
6
|
+
|
|
7
|
+
1. Use SDK iterator helpers when available, for example `recordsWithIterator`, `recordsAcrossObjectsWithIterator`, or `dataset.listWithIterator`.
|
|
8
|
+
2. If the endpoint supports `page_token` / `next_page_token`, use token pagination.
|
|
9
|
+
3. If only `limit` / `offset` is available, use ID cursor pagination with `_id`.
|
|
10
|
+
|
|
11
|
+
## ID Cursor Pattern
|
|
12
|
+
|
|
13
|
+
Keep `offset: 0`, set `count: false`, filter `_id > lastId`, and sort `_id asc`.
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
let lastId = 0;
|
|
17
|
+
const limit = 200;
|
|
18
|
+
const all: any[] = [];
|
|
19
|
+
|
|
20
|
+
while (true) {
|
|
21
|
+
const res = await client.constant.records({
|
|
22
|
+
object_name: "_currency",
|
|
23
|
+
data: {
|
|
24
|
+
offset: 0,
|
|
25
|
+
limit,
|
|
26
|
+
count: false,
|
|
27
|
+
fields: ["_id", "_name"],
|
|
28
|
+
filter: [{ leftValue: "_id", operator: "gt", rightValue: lastId }],
|
|
29
|
+
sort: [{ field: "_id", direction: "asc" }]
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
if (res.code !== "0") throw new Error(res.msg || "query failed");
|
|
34
|
+
|
|
35
|
+
const records = res.data?.records || res.data?.items || [];
|
|
36
|
+
all.push(...records);
|
|
37
|
+
if (records.length < limit) break;
|
|
38
|
+
|
|
39
|
+
lastId = records[records.length - 1]._id;
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Page Token Pattern
|
|
44
|
+
|
|
45
|
+
For record query endpoints that support token pagination:
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
const { items } = await client.object.search.recordsWithIterator({
|
|
49
|
+
object_name: "object_store",
|
|
50
|
+
data: {
|
|
51
|
+
page_size: 100,
|
|
52
|
+
use_page_token: true,
|
|
53
|
+
select: ["_id", "name"],
|
|
54
|
+
query_deleted_record: false
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Rules
|
|
60
|
+
|
|
61
|
+
- Do not parallelize high-offset reads.
|
|
62
|
+
- Do not request `total` or `count` unless the user actually needs it.
|
|
63
|
+
- Always sort by `_id asc` when using `_id` as the cursor.
|
|
64
|
+
- Stop only when the returned page has fewer records than `limit` or when `has_more` is false.
|
|
@@ -17,25 +17,41 @@ Use this skill for `client.schema.*`.
|
|
|
17
17
|
1. Use `apaas-shared` to initialize the client.
|
|
18
18
|
2. Read current objects with `client.object.listWithIterator()`.
|
|
19
19
|
3. Read existing fields with `client.object.metadata.fields({ object_name })`.
|
|
20
|
-
4.
|
|
21
|
-
5.
|
|
22
|
-
6. Check
|
|
23
|
-
7. After the call,
|
|
20
|
+
4. Prefer `client.schema.createWithStages()` for new objects with fields.
|
|
21
|
+
5. Use `client.schema.addFieldsIdempotent()` when adding fields to an existing object.
|
|
22
|
+
6. Check raw schema write responses with `client.schema.checkResponse()`.
|
|
23
|
+
7. After the call, use `client.schema.verifyObjects()` to verify the effective schema.
|
|
24
24
|
|
|
25
25
|
## Create Object
|
|
26
26
|
|
|
27
|
-
Create objects
|
|
27
|
+
Create objects through the SDK staging helper when fields are involved. It creates shells first, then base fields, then lookup fields, then reference fields, then final settings.
|
|
28
28
|
|
|
29
29
|
```ts
|
|
30
|
-
await client.schema.
|
|
30
|
+
await client.schema.createWithStages({
|
|
31
31
|
objects: [{
|
|
32
32
|
api_name: "product",
|
|
33
33
|
label: { zh_cn: "产品", en_us: "Product" },
|
|
34
34
|
settings: {
|
|
35
|
-
display_name: "
|
|
36
|
-
allow_search_fields: ["_id"],
|
|
35
|
+
display_name: "name",
|
|
36
|
+
allow_search_fields: ["_id", "name"],
|
|
37
37
|
search_layout: []
|
|
38
|
-
}
|
|
38
|
+
},
|
|
39
|
+
fields: [{
|
|
40
|
+
operator: "add",
|
|
41
|
+
api_name: "name",
|
|
42
|
+
label: { zh_cn: "产品名称", en_us: "Name" },
|
|
43
|
+
type: {
|
|
44
|
+
name: "text",
|
|
45
|
+
settings: {
|
|
46
|
+
required: true,
|
|
47
|
+
unique: false,
|
|
48
|
+
case_sensitive: false,
|
|
49
|
+
multiline: false,
|
|
50
|
+
max_length: 100
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
encrypt_type: "none"
|
|
54
|
+
}]
|
|
39
55
|
}]
|
|
40
56
|
});
|
|
41
57
|
```
|
|
@@ -48,19 +64,23 @@ await client.schema.create({
|
|
|
48
64
|
- Update label/settings without field changes by omitting `fields`.
|
|
49
65
|
|
|
50
66
|
```ts
|
|
51
|
-
await client.schema.
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
67
|
+
await client.schema.addFieldsIdempotent({
|
|
68
|
+
object_name: "product",
|
|
69
|
+
fields: [{
|
|
70
|
+
operator: "add",
|
|
71
|
+
api_name: "description",
|
|
72
|
+
label: { zh_cn: "产品描述", en_us: "Description" },
|
|
73
|
+
type: {
|
|
74
|
+
name: "text",
|
|
75
|
+
settings: {
|
|
76
|
+
required: false,
|
|
77
|
+
unique: false,
|
|
78
|
+
case_sensitive: false,
|
|
79
|
+
multiline: true,
|
|
80
|
+
max_length: 100000
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
encrypt_type: "none"
|
|
64
84
|
}]
|
|
65
85
|
});
|
|
66
86
|
```
|
|
@@ -70,3 +90,4 @@ await client.schema.update({
|
|
|
70
90
|
- Confirm the object API names before `client.schema.delete`.
|
|
71
91
|
- Do not delete objects as a cleanup shortcut if records or references may still depend on them.
|
|
72
92
|
- Remove `reference_field` before removing its lookup field.
|
|
93
|
+
- For environment rebuilds, use `client.schema.deleteAllCustomObjects({ confirm: true })`.
|
|
@@ -104,9 +104,32 @@ blue, cyan, green, yellow, orange, red, magenta, purple, blueMagenta, grey, blue
|
|
|
104
104
|
}
|
|
105
105
|
```
|
|
106
106
|
|
|
107
|
+
OpenAPI write payloads require color short codes, while metadata returns color names. The SDK normalizes these names before writing, so SDK callers can keep using `blue`, `cyan`, etc.
|
|
108
|
+
|
|
109
|
+
| Metadata color | OpenAPI write code |
|
|
110
|
+
|---|---|
|
|
111
|
+
| `blue` | `B` |
|
|
112
|
+
| `cyan` | `W` |
|
|
113
|
+
| `green` | `G` |
|
|
114
|
+
| `yellow` | `Y` |
|
|
115
|
+
| `orange` | `O` |
|
|
116
|
+
| `red` | `R` |
|
|
117
|
+
| `magenta` | `V` |
|
|
118
|
+
| `purple` | `P` |
|
|
119
|
+
| `blueMagenta` | `I` |
|
|
120
|
+
| `grey` | `N` |
|
|
121
|
+
|
|
107
122
|
Do not copy metadata `optionList` back into `schema.update`; convert it to `options`.
|
|
108
123
|
|
|
109
|
-
Use `getOptionColor(index)` from the SDK to assign
|
|
124
|
+
Use `getOptionColor(index)` from the SDK to assign metadata color names in this stable 10-color cycle. Use `getOptionColorCode(color)` only when constructing raw OpenAPI payloads outside the SDK normalizer.
|
|
125
|
+
|
|
126
|
+
## SQL Conversion Constants
|
|
127
|
+
|
|
128
|
+
For SQL/ER conversion, use the SDK exports instead of retyping mapping tables:
|
|
129
|
+
|
|
130
|
+
- `SQL_TYPE_TO_SCHEMA_TYPE`
|
|
131
|
+
- `COLUMN_NAME_SEMANTIC_RULES`
|
|
132
|
+
- `SQL_CONSTRAINT_TO_SETTINGS`
|
|
110
133
|
|
|
111
134
|
## Minimal Lookup Example
|
|
112
135
|
|
|
@@ -13,30 +13,17 @@ Use this reference for whole-application object maintenance: reading object stru
|
|
|
13
13
|
|
|
14
14
|
## Response Validation
|
|
15
15
|
|
|
16
|
-
Check three layers after every schema call:
|
|
16
|
+
Check three layers after every raw schema call with the SDK helper:
|
|
17
17
|
|
|
18
18
|
```ts
|
|
19
|
-
|
|
20
|
-
if (result.code !== "0") {
|
|
21
|
-
throw new Error(`${context} request failed: ${result.code} ${result.msg || ""}`);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
if (result.data === null) {
|
|
25
|
-
throw new Error(`${context} silently failed: result.code is 0 but result.data is null`);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const failed = (result.data?.items || []).filter((item: any) => item.status?.code !== "0");
|
|
29
|
-
if (failed.length > 0) {
|
|
30
|
-
throw new Error(`${context} item failures: ${JSON.stringify(failed)}`);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
19
|
+
client.schema.checkResponse(result, "schema.update");
|
|
33
20
|
```
|
|
34
21
|
|
|
35
22
|
`code: "0"` with `data: null` is not success. It usually means a required setting is missing, for example `text.multiline` or `auto_number.generation_method`.
|
|
36
23
|
|
|
37
24
|
## Create Objects: Three Stages
|
|
38
25
|
|
|
39
|
-
Do not create a full object with fields
|
|
26
|
+
Do not create a full object with raw `schema.create({ fields })`. Use `client.schema.createWithStages()` when fields are involved. It enforces this sequence even when there is no obvious dependency cycle.
|
|
40
27
|
|
|
41
28
|
1. Stage 1a: create object shells only.
|
|
42
29
|
2. Stage 1b: add base fields with `schema.update` and `operator: "add"`.
|
|
@@ -45,19 +32,11 @@ Do not create a full object with fields in one call. Use this sequence even when
|
|
|
45
32
|
5. Final: update `display_name`, `allow_search_fields`, and `search_layout` after fields exist.
|
|
46
33
|
|
|
47
34
|
```ts
|
|
48
|
-
await client.schema.
|
|
35
|
+
await client.schema.createWithStages({
|
|
49
36
|
objects: [{
|
|
50
37
|
api_name: "customer",
|
|
51
38
|
label: { zh_cn: "客户", en_us: "Customer" },
|
|
52
|
-
settings: { display_name: "
|
|
53
|
-
}]
|
|
54
|
-
});
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
```ts
|
|
58
|
-
await client.schema.update({
|
|
59
|
-
objects: [{
|
|
60
|
-
api_name: "customer",
|
|
39
|
+
settings: { display_name: "name", allow_search_fields: ["_id", "name"], search_layout: [] },
|
|
61
40
|
fields: [{
|
|
62
41
|
operator: "add",
|
|
63
42
|
api_name: "name",
|
|
@@ -86,14 +65,10 @@ await client.schema.update({
|
|
|
86
65
|
- Skip existing fields when rerunning idempotently.
|
|
87
66
|
|
|
88
67
|
```ts
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if (newFields.length === 0) return;
|
|
94
|
-
const result = await client.schema.update({ objects: [{ api_name: objectName, fields: newFields }] });
|
|
95
|
-
checkSchemaResponse(result, `addFields(${objectName})`);
|
|
96
|
-
}
|
|
68
|
+
await client.schema.addFieldsIdempotent({
|
|
69
|
+
object_name: "customer",
|
|
70
|
+
fields: fieldsToAdd
|
|
71
|
+
});
|
|
97
72
|
```
|
|
98
73
|
|
|
99
74
|
## Dependency Order
|
|
@@ -116,15 +91,16 @@ Never add a lookup and a reference field that depends on it in the same `schema.
|
|
|
116
91
|
|
|
117
92
|
## Delete All Custom Objects
|
|
118
93
|
|
|
119
|
-
Use
|
|
94
|
+
Use the SDK helper for environment cleanup or model rebuilds:
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
await client.schema.deleteAllCustomObjects({
|
|
98
|
+
confirm: true,
|
|
99
|
+
removeOtherFields: true
|
|
100
|
+
});
|
|
101
|
+
```
|
|
120
102
|
|
|
121
|
-
|
|
122
|
-
2. Filter out system objects whose API name starts with `_`.
|
|
123
|
-
3. Read fields for each custom object.
|
|
124
|
-
4. Remove `referenceField` fields grouped by object.
|
|
125
|
-
5. Remove `lookup` fields grouped by object.
|
|
126
|
-
6. Delete custom objects in batches of 10.
|
|
127
|
-
7. Re-list objects to verify deletion.
|
|
103
|
+
The helper lists custom objects, reads fields, removes `referenceField`, then `lookup`, then optional other custom fields, deletes objects in batches of 10, and re-lists objects to verify deletion.
|
|
128
104
|
|
|
129
105
|
## SQL / ER To aPaaS Mapping
|
|
130
106
|
|