apaas-oapi-client 0.1.37 → 0.1.39

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 CHANGED
@@ -30,6 +30,48 @@
30
30
 
31
31
  ---
32
32
 
33
+ ## 🤖 **AI Agent / Skills**
34
+
35
+ 本仓库内置面向 AI Agent 的模块化 Skills,路径为 [skills](./skills)。设计采用 `shared + domain skill + references` 的轻量结构:主 `SKILL.md` 负责路由和安全边界,复杂规则放到 `references/` 按需读取。
36
+
37
+ | Skill | 适用场景 |
38
+ | --- | --- |
39
+ | `apaas-shared` | Client 初始化、凭证安全、namespace、token、日志、分页与错误处理 |
40
+ | `apaas-object` | 对象列表、字段元数据、记录查询/创建/更新/删除、Markdown 导出 |
41
+ | `apaas-schema` | 对象和字段结构管理、字段类型映射、lookup/reference 依赖规则 |
42
+ | `apaas-function-flow` | 云函数调用、自动化流程 v1/v2 执行 |
43
+ | `apaas-builder` | 页面列表、页面详情、页面访问链接 |
44
+ | `apaas-global` | 全局选项、环境变量读取与审计 |
45
+ | `apaas-exchange-attachment` | 用户/部门 ID 交换、附件和头像上传下载 |
46
+
47
+ 从仓库根目录安装到 Codex Skill 目录:
48
+
49
+ ```bash
50
+ mkdir -p "${CODEX_HOME:-$HOME/.codex}/skills"
51
+ cp -R skills/apaas-* "${CODEX_HOME:-$HOME/.codex}/skills/"
52
+ ```
53
+
54
+ 通过 npx 从 npm 直接安装:
55
+
56
+ ```bash
57
+ npx apaas-oapi-client install-skills
58
+ ```
59
+
60
+ 从已安装 npm 包的项目安装:
61
+
62
+ ```bash
63
+ mkdir -p "${CODEX_HOME:-$HOME/.codex}/skills"
64
+ cp -R node_modules/apaas-oapi-client/skills/apaas-* "${CODEX_HOME:-$HOME/.codex}/skills/"
65
+ ```
66
+
67
+ 使用建议:
68
+
69
+ - 写入前先用 `apaas-object` 读取真实 metadata。
70
+ - Schema 字段变更前先读 `apaas-schema/references/field-schema-rules.md`。
71
+ - 删除、批量写入、流程执行都按写操作处理,先确认目标和影响。
72
+
73
+ ---
74
+
33
75
  ## 📦 **安装**
34
76
 
35
77
  ```bash
@@ -38,7 +80,7 @@ npm install apaas-oapi-client
38
80
 
39
81
  ---
40
82
 
41
- ## **快速开始**
83
+ ## 🚀 **快速开始**
42
84
 
43
85
  ### 创建数据对象
44
86
 
@@ -0,0 +1,129 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require("fs");
4
+ const os = require("os");
5
+ const path = require("path");
6
+
7
+ const packageRoot = path.resolve(__dirname, "..");
8
+ const skillsRoot = path.join(packageRoot, "skills");
9
+
10
+ function usage() {
11
+ console.log(`Usage:
12
+ npx apaas-oapi-client install-skills [--target <dir>] [--dry-run]
13
+
14
+ Commands:
15
+ install-skills Install bundled aPaaS Codex skills.
16
+
17
+ Options:
18
+ --target <dir> Skill install directory. Defaults to $CODEX_HOME/skills or ~/.codex/skills.
19
+ --dry-run Print planned copies without writing files.
20
+ -h, --help Show this help.`);
21
+ }
22
+
23
+ function parseArgs(argv) {
24
+ const args = {
25
+ command: argv[0],
26
+ target: process.env.CODEX_HOME
27
+ ? path.join(process.env.CODEX_HOME, "skills")
28
+ : path.join(os.homedir(), ".codex", "skills"),
29
+ dryRun: false
30
+ };
31
+
32
+ if (args.command === "-h" || args.command === "--help") {
33
+ args.command = "help";
34
+ return args;
35
+ }
36
+
37
+ for (let i = 1; i < argv.length; i += 1) {
38
+ const arg = argv[i];
39
+
40
+ if (arg === "--dry-run") {
41
+ args.dryRun = true;
42
+ continue;
43
+ }
44
+
45
+ if (arg === "--target") {
46
+ const target = argv[i + 1];
47
+ if (!target) {
48
+ throw new Error("--target requires a directory");
49
+ }
50
+ args.target = path.resolve(target);
51
+ i += 1;
52
+ continue;
53
+ }
54
+
55
+ if (arg === "-h" || arg === "--help") {
56
+ args.command = "help";
57
+ continue;
58
+ }
59
+
60
+ throw new Error(`Unknown option: ${arg}`);
61
+ }
62
+
63
+ return args;
64
+ }
65
+
66
+ function listBundledSkills() {
67
+ if (!fs.existsSync(skillsRoot)) {
68
+ throw new Error(`Bundled skills directory not found: ${skillsRoot}`);
69
+ }
70
+
71
+ return fs.readdirSync(skillsRoot, { withFileTypes: true })
72
+ .filter(entry => entry.isDirectory() && entry.name.startsWith("apaas-"))
73
+ .map(entry => entry.name)
74
+ .sort();
75
+ }
76
+
77
+ function installSkills(args) {
78
+ const skillNames = listBundledSkills();
79
+
80
+ if (skillNames.length === 0) {
81
+ throw new Error(`No bundled apaas-* skills found in ${skillsRoot}`);
82
+ }
83
+
84
+ console.log(`Installing ${skillNames.length} aPaaS skill(s) to ${args.target}`);
85
+
86
+ if (!args.dryRun) {
87
+ fs.mkdirSync(args.target, { recursive: true });
88
+ }
89
+
90
+ for (const skillName of skillNames) {
91
+ const source = path.join(skillsRoot, skillName);
92
+ const target = path.join(args.target, skillName);
93
+ console.log(`${args.dryRun ? "Would copy" : "Copying"} ${skillName}`);
94
+
95
+ if (!args.dryRun) {
96
+ fs.cpSync(source, target, {
97
+ recursive: true,
98
+ force: true,
99
+ errorOnExist: false
100
+ });
101
+ }
102
+ }
103
+
104
+ console.log(args.dryRun ? "Dry run complete." : "Done. Restart or refresh Codex to load the skills.");
105
+ }
106
+
107
+ function main() {
108
+ const args = parseArgs(process.argv.slice(2));
109
+
110
+ if (!args.command || args.command === "help") {
111
+ usage();
112
+ return;
113
+ }
114
+
115
+ if (args.command !== "install-skills") {
116
+ throw new Error(`Unknown command: ${args.command}`);
117
+ }
118
+
119
+ installSkills(args);
120
+ }
121
+
122
+ try {
123
+ main();
124
+ } catch (error) {
125
+ console.error(error instanceof Error ? error.message : String(error));
126
+ console.error("");
127
+ usage();
128
+ process.exitCode = 1;
129
+ }
package/package.json CHANGED
@@ -1,7 +1,10 @@
1
1
  {
2
2
  "name": "apaas-oapi-client",
3
- "version": "0.1.37",
3
+ "version": "0.1.39",
4
4
  "main": "dist/index.js",
5
+ "bin": {
6
+ "apaas-oapi-client": "./bin/apaas-oapi-client.js"
7
+ },
5
8
  "exports": {
6
9
  ".": "./dist/index.js",
7
10
  "./node-sdk": "./dist/index.js"
@@ -14,8 +17,19 @@
14
17
  "dev": "tsx src/index.ts",
15
18
  "release": "npm run build && npm version patch && git push origin main --follow-tags"
16
19
  },
17
- "keywords": [],
20
+ "keywords": [
21
+ "apaas",
22
+ "openapi",
23
+ "nodejs",
24
+ "sdk",
25
+ "ai-agent",
26
+ "codex-skill"
27
+ ],
18
28
  "author": "",
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "https://github.com/ennann/apaas-oapi-node-client"
32
+ },
19
33
  "license": "ISC",
20
34
  "dependencies": {
21
35
  "axios": "^1.10.0",
@@ -35,5 +49,5 @@
35
49
  "tsx": "^4.21.0",
36
50
  "typescript": "^5.8.3"
37
51
  },
38
- "description": ""
52
+ "description": "aPaaS OpenAPI Node.js 客户端 SDK,内置 AI Agent 友好的模块化 Skills 与 Schema 辅助规则。"
39
53
  }
@@ -0,0 +1,43 @@
1
+ ---
2
+ name: apaas-builder
3
+ description: "Use for aPaaS Node SDK builder page operations: listing pages, paginating page metadata, reading page details, generating page access URLs with pageParams, parentPageParams, navId, or tabId, and verifying page IDs from live metadata."
4
+ ---
5
+
6
+ # aPaaS Builder
7
+
8
+ Use this skill for `client.page.*`.
9
+
10
+ ## Resolve Page IDs
11
+
12
+ Start from live page metadata unless the user provides a confirmed page ID.
13
+
14
+ ```ts
15
+ const { items } = await client.page.listWithIterator({ limit: 100 });
16
+ const target = items.find(page => page.name === "门店详情");
17
+ ```
18
+
19
+ Use returned `page_id` values in follow-up calls.
20
+
21
+ ## Page Detail
22
+
23
+ ```ts
24
+ const detail = await client.page.detail({
25
+ page_id: "page_id"
26
+ });
27
+ ```
28
+
29
+ Use detail reads before generating links that require route parameters.
30
+
31
+ ## Page URL
32
+
33
+ ```ts
34
+ const url = await client.page.url({
35
+ page_id: "page_id",
36
+ pageParams: { id: "record_id" },
37
+ parentPageParams: {},
38
+ navId: "nav_id",
39
+ tabId: "tab_id"
40
+ });
41
+ ```
42
+
43
+ Only include optional parameters that are required by the target page. Verify generated URLs by opening them or handing them to the user with the relevant page and record context.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "aPaaS Builder"
3
+ short_description: "aPaaS 页面元数据、详情和访问链接生成操作指南"
4
+ default_prompt: "Use $apaas-builder to inspect pages and generate page links with the aPaaS Node SDK."
@@ -0,0 +1,59 @@
1
+ ---
2
+ name: apaas-exchange-attachment
3
+ description: "Use for aPaaS Node SDK identity exchange and attachment operations: department ID exchange, user ID exchange, batch exchange with retry results, file upload/download/delete, avatar image upload/download, and safe handling of IDs and binary payloads."
4
+ ---
5
+
6
+ # aPaaS Exchange Attachment
7
+
8
+ Use this skill for `client.department.*`, `client.user.*`, and `client.attachment.*`.
9
+
10
+ ## Department Exchange
11
+
12
+ ```ts
13
+ const department = await client.department.exchange({
14
+ department_id_type: "department_id",
15
+ department_id: "1758534140403815"
16
+ });
17
+
18
+ const batch = await client.department.batchExchange({
19
+ department_id_type: "external_department_id",
20
+ department_ids: ["dept-a", "dept-b"]
21
+ });
22
+ ```
23
+
24
+ Check `failedCount` after batch exchange.
25
+
26
+ ## User Exchange
27
+
28
+ ```ts
29
+ const user = await client.user.exchange({
30
+ user_id_type: "external_open_id",
31
+ user_id: "ou_xxx",
32
+ feishu_app_id: "cli_xxx"
33
+ });
34
+
35
+ const batch = await client.user.batchExchange({
36
+ user_id_type: "external_user_id",
37
+ user_ids: ["u1", "u2"],
38
+ feishu_app_id: "cli_xxx"
39
+ });
40
+ ```
41
+
42
+ Use real `feishu_app_id`; do not guess it from namespace.
43
+
44
+ ## Attachments
45
+
46
+ ```ts
47
+ const uploaded = await client.attachment.file.upload({ file });
48
+ const data = await client.attachment.file.download({ file_id: "file_token" });
49
+ await client.attachment.file.delete({ file_id: "file_token" });
50
+
51
+ const avatar = await client.attachment.avatar.upload({ image });
52
+ const imageData = await client.attachment.avatar.download({ image_id: "image_token" });
53
+ ```
54
+
55
+ ## Safety
56
+
57
+ - Confirm deletes before calling `attachment.file.delete`.
58
+ - Do not print binary payloads, raw access tokens, or private file contents.
59
+ - For record attachment fields, read object metadata first and write only the field shape expected by the platform.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "aPaaS Exchange Attachment"
3
+ short_description: "aPaaS 用户部门 ID 交换和附件处理操作指南"
4
+ default_prompt: "Use $apaas-exchange-attachment to exchange IDs or handle attachments with the aPaaS Node SDK."
@@ -0,0 +1,50 @@
1
+ ---
2
+ name: apaas-function-flow
3
+ description: "Use for aPaaS Node SDK cloud function and automation flow execution: invoking functions, executing v1/v2 flows, preparing operator payloads, checking returned code/msg/data, and avoiding unsafe repeated workflow submissions."
4
+ ---
5
+
6
+ # aPaaS Function Flow
7
+
8
+ Use this skill for `client.function.*` and `client.automation.*`.
9
+
10
+ ## Function Invoke
11
+
12
+ Use when the target is a named cloud function and the caller already knows the function contract.
13
+
14
+ ```ts
15
+ const res = await client.function.invoke({
16
+ name: "SyncStoreManager",
17
+ params: {
18
+ store_id: "record_id"
19
+ }
20
+ });
21
+
22
+ if (res.code !== "0") {
23
+ throw new Error(res.msg || "function invoke failed");
24
+ }
25
+ ```
26
+
27
+ ## Automation Flow
28
+
29
+ Use `automation.v1.execute` only for v1 flow endpoints and `automation.v2.execute` for v2 endpoints. Always pass an explicit operator object from a real user record or documented service account.
30
+
31
+ ```ts
32
+ const res = await client.automation.v2.execute({
33
+ flow_api_name: "store_manager_change",
34
+ operator: {
35
+ _id: 123456,
36
+ email: "operator@example.com"
37
+ },
38
+ params: {
39
+ store_id: "record_id",
40
+ new_manager_id: "user_record_id"
41
+ }
42
+ });
43
+ ```
44
+
45
+ ## Safety
46
+
47
+ - Treat flow execution as a write operation; confirm before triggering production workflows.
48
+ - Do not resubmit failed flows with `is_resubmit` unless the user explicitly requests it and `pre_instance_id` is known.
49
+ - Log flow/function names and result codes, not secrets or full sensitive payloads.
50
+ - If the flow mutates records, verify the target record after execution with `apaas-object`.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "aPaaS Function Flow"
3
+ short_description: "aPaaS 云函数调用和自动化流程执行安全操作指南"
4
+ default_prompt: "Use $apaas-function-flow to invoke cloud functions or automation flows."
@@ -0,0 +1,43 @@
1
+ ---
2
+ name: apaas-global
3
+ description: "Use for aPaaS Node SDK global data operations: reading global option details, listing global options, reading global variable details, listing global variables, paginating results, and resolving API names from live metadata."
4
+ ---
5
+
6
+ # aPaaS Global
7
+
8
+ Use this skill for `client.global.*`.
9
+
10
+ ## Global Options
11
+
12
+ ```ts
13
+ const option = await client.global.options.detail({
14
+ api_name: "store_status"
15
+ });
16
+
17
+ const { total, items } = await client.global.options.listWithIterator({
18
+ limit: 100,
19
+ filter: { quickQuery: "status" }
20
+ });
21
+ ```
22
+
23
+ Use global options to validate enum-like values before writing records or schema.
24
+
25
+ ## Global Variables
26
+
27
+ ```ts
28
+ const variable = await client.global.variables.detail({
29
+ api_name: "current_region"
30
+ });
31
+
32
+ const variables = await client.global.variables.listWithIterator({
33
+ limit: 100
34
+ });
35
+ ```
36
+
37
+ Do not expose secrets from global variables. When reporting results, summarize key names and operational meaning instead of raw secret values.
38
+
39
+ ## Rules
40
+
41
+ - Use `listWithIterator` for inventory or audit tasks.
42
+ - Use `detail` when an exact API name is known.
43
+ - Treat missing global values as configuration problems, not SDK bugs, until live metadata proves otherwise.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "aPaaS Global"
3
+ short_description: "aPaaS 全局选项和环境变量读取审计安全操作指南"
4
+ default_prompt: "Use $apaas-global to inspect global options and variables with the aPaaS Node SDK."
@@ -0,0 +1,99 @@
1
+ ---
2
+ name: apaas-object
3
+ description: "Use for aPaaS Node SDK object metadata and record operations: listing objects, reading fields, exporting metadata to Markdown, querying records, count, create, update, delete, batch operations, pagination, and record-level error recovery."
4
+ ---
5
+
6
+ # aPaaS Object
7
+
8
+ Use this skill for `client.object.*`.
9
+
10
+ ## Workflow
11
+
12
+ 1. Initialize the client with `apaas-shared`.
13
+ 2. Resolve object and field API names from live metadata.
14
+ 3. Read before write when the payload depends on field type or readonly status.
15
+ 4. Use iterator helpers for full-result work.
16
+ 5. Check SDK response codes and failed item lists.
17
+
18
+ ## Metadata
19
+
20
+ Prefer metadata calls before record work:
21
+
22
+ ```ts
23
+ const objects = await client.object.listWithIterator({
24
+ filter: { type: "custom", quickQuery: "store" },
25
+ limit: 50
26
+ });
27
+
28
+ const fields = await client.object.metadata.fields({
29
+ object_name: "object_store"
30
+ });
31
+
32
+ const markdown = await client.object.metadata.export2markdown({
33
+ object_names: ["object_store", "_user"]
34
+ });
35
+ ```
36
+
37
+ Use returned API names, not user-facing labels, in later calls.
38
+
39
+ ## Record Reads
40
+
41
+ - Use `search.record` for one known record ID.
42
+ - Use `search.records` for one page.
43
+ - Use `search.recordsWithIterator` for full-table or full-filter tasks.
44
+ - Use `search.count` when only the count is needed.
45
+
46
+ ```ts
47
+ const { total, items } = await client.object.search.recordsWithIterator({
48
+ object_name: "object_store",
49
+ data: {
50
+ need_total_count: true,
51
+ page_size: 100,
52
+ offset: 0,
53
+ select: ["_id", "store_code", "store_name"],
54
+ use_page_token: true
55
+ }
56
+ });
57
+ ```
58
+
59
+ Do not answer global max/min/top/count questions from a single page unless the user asked for a sample.
60
+
61
+ ## Record Writes
62
+
63
+ Use storage fields only. Re-read metadata when unsure.
64
+
65
+ ```ts
66
+ await client.object.create.record({
67
+ object_name: "object_event_log",
68
+ record: {
69
+ name: "sync_started",
70
+ content: "nightly job started"
71
+ }
72
+ });
73
+
74
+ await client.object.update.record({
75
+ object_name: "object_store",
76
+ record_id: "record_id",
77
+ record: { store_name: "新门店名称" }
78
+ });
79
+ ```
80
+
81
+ For large batches, use `recordsWithIterator` helpers and inspect failures:
82
+
83
+ ```ts
84
+ const result = await client.object.update.recordsWithIterator({
85
+ object_name: "object_store",
86
+ records,
87
+ limit: 100
88
+ });
89
+
90
+ if (result.failedCount > 0) {
91
+ console.warn(result.failed);
92
+ }
93
+ ```
94
+
95
+ ## Delete Rules
96
+
97
+ - Confirm target object and record IDs before delete.
98
+ - Prefer `delete.recordsWithIterator` for large deletes so partial failures are visible.
99
+ - Report `successCount`, `failedCount`, and failed IDs after batch deletion.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "aPaaS Object"
3
+ short_description: "aPaaS 对象元数据、记录读写与分页查询操作指南"
4
+ default_prompt: "Use $apaas-object to read metadata and operate records with the aPaaS Node SDK."
@@ -0,0 +1,77 @@
1
+ ---
2
+ name: apaas-schema
3
+ description: "Use for aPaaS Node SDK schema management: creating objects, updating object labels/settings, adding/replacing/removing fields, deleting objects, field type mapping, lookup/reference field dependencies, and schema change safety checks."
4
+ ---
5
+
6
+ # aPaaS Schema
7
+
8
+ Use this skill for `client.schema.*`.
9
+
10
+ ## Required Reference
11
+
12
+ Before creating or updating fields, read `references/field-schema-rules.md`. It contains the verified metadata-to-create type mapping and dependency order.
13
+
14
+ ## Workflow
15
+
16
+ 1. Use `apaas-shared` to initialize the client.
17
+ 2. Read current objects with `client.object.listWithIterator()`.
18
+ 3. Read existing fields with `client.object.metadata.fields({ object_name })`.
19
+ 4. Build the smallest schema payload that matches the requested change.
20
+ 5. For dependency fields, create target objects first, then lookup fields, then reference fields.
21
+ 6. After the call, re-read metadata to verify the effective schema.
22
+
23
+ ## Create Object
24
+
25
+ ```ts
26
+ await client.schema.create({
27
+ objects: [{
28
+ api_name: "product",
29
+ label: { zh_cn: "产品", en_us: "Product" },
30
+ settings: {
31
+ display_name: "name",
32
+ allow_search_fields: ["_id", "code", "name"],
33
+ search_layout: ["code", "name"]
34
+ },
35
+ fields: [{
36
+ api_name: "code",
37
+ label: { zh_cn: "产品编号", en_us: "Product Code" },
38
+ type: {
39
+ name: "text",
40
+ settings: { required: true, unique: true, max_length: 50 }
41
+ },
42
+ encrypt_type: "none"
43
+ }]
44
+ }]
45
+ });
46
+ ```
47
+
48
+ ## Update Object Or Fields
49
+
50
+ - Add field: `operator: "add"` and full field definition.
51
+ - Replace field: `operator: "replace"` and full `type.name + type.settings`.
52
+ - Remove field: `operator: "remove"` and `api_name` only.
53
+ - Update label/settings without field changes by omitting `fields`.
54
+
55
+ ```ts
56
+ await client.schema.update({
57
+ objects: [{
58
+ api_name: "product",
59
+ fields: [{
60
+ operator: "add",
61
+ api_name: "description",
62
+ label: { zh_cn: "产品描述", en_us: "Description" },
63
+ type: {
64
+ name: "text",
65
+ settings: { multiline: true, max_length: 100000 }
66
+ },
67
+ encrypt_type: "none"
68
+ }]
69
+ }]
70
+ });
71
+ ```
72
+
73
+ ## Delete Rules
74
+
75
+ - Confirm the object API names before `client.schema.delete`.
76
+ - Do not delete objects as a cleanup shortcut if records or references may still depend on them.
77
+ - Remove `reference_field` before removing its lookup field.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "aPaaS Schema"
3
+ short_description: "aPaaS 对象、字段结构和类型规则管理安全操作指南"
4
+ default_prompt: "Use $apaas-schema to create or update aPaaS object schemas safely."