@carthooks/arcubase-cli 0.1.10 → 0.1.12
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/bundle/arcubase-admin.mjs +1274 -375
- package/bundle/arcubase.mjs +1274 -375
- package/dist/generated/command_registry.generated.d.ts +36 -35
- package/dist/generated/command_registry.generated.d.ts.map +1 -1
- package/dist/generated/command_registry.generated.js +37 -36
- package/dist/generated/type_index.generated.d.ts +23 -23
- package/dist/generated/type_index.generated.js +23 -23
- package/dist/runtime/entity_save_schema.d.ts.map +1 -1
- package/dist/runtime/entity_save_schema.js +30 -0
- package/dist/runtime/env.d.ts +2 -1
- package/dist/runtime/env.d.ts.map +1 -1
- package/dist/runtime/env.js +10 -1
- package/dist/runtime/errors.d.ts +2 -0
- package/dist/runtime/errors.d.ts.map +1 -1
- package/dist/runtime/execute.d.ts +4 -2
- package/dist/runtime/execute.d.ts.map +1 -1
- package/dist/runtime/execute.js +944 -134
- package/dist/runtime/paths.d.ts +1 -1
- package/dist/runtime/paths.d.ts.map +1 -1
- package/dist/runtime/paths.js +9 -2
- package/dist/runtime/upload.d.ts +1 -11
- package/dist/runtime/upload.d.ts.map +1 -1
- package/dist/runtime/upload.js +19 -133
- package/dist/runtime/zod_registry.d.ts +5 -3
- package/dist/runtime/zod_registry.d.ts.map +1 -1
- package/dist/runtime/zod_registry.js +108 -48
- package/dist/tests/bootstrap.test.js +12 -0
- package/dist/tests/command_registry.test.js +8 -0
- package/dist/tests/docs_readability.test.d.ts +2 -0
- package/dist/tests/docs_readability.test.d.ts.map +1 -0
- package/dist/tests/docs_readability.test.js +87 -0
- package/dist/tests/entity_save_schema.test.js +22 -0
- package/dist/tests/execute_validation.test.js +381 -44
- package/dist/tests/help.test.js +45 -8
- package/dist/tests/upload.test.js +30 -77
- package/package.json +1 -1
- package/sdk-dist/docs/runtime-reference/README.md +43 -29
- package/sdk-dist/docs/runtime-reference/access-rule.md +109 -0
- package/sdk-dist/docs/runtime-reference/condition.md +182 -0
- package/sdk-dist/docs/runtime-reference/entity-schema/README.md +6 -5
- package/sdk-dist/docs/runtime-reference/entity-schema/checkbox.md +1 -1
- package/sdk-dist/docs/runtime-reference/entity-schema/file.md +2 -2
- package/sdk-dist/docs/runtime-reference/entity-schema/image.md +2 -2
- package/sdk-dist/docs/runtime-reference/entity-schema/linkto.md +3 -3
- package/sdk-dist/docs/runtime-reference/entity-schema/number.md +1 -1
- package/sdk-dist/docs/runtime-reference/entity-schema/query.md +3 -3
- package/sdk-dist/docs/runtime-reference/entity-schema/relation.md +3 -3
- package/sdk-dist/docs/runtime-reference/entity-schema/relationfield.md +3 -3
- package/sdk-dist/docs/runtime-reference/entity-schema/status.md +1 -1
- package/sdk-dist/docs/runtime-reference/entity-schema/text.md +1 -1
- package/sdk-dist/docs/runtime-reference/entity-schema.md +28 -21
- package/sdk-dist/docs/runtime-reference/examples/README.md +1 -1
- package/sdk-dist/docs/runtime-reference/examples/crm-01/README.md +30 -11
- package/sdk-dist/docs/runtime-reference/examples/crm-01/contact.create-entity.json +1 -0
- package/sdk-dist/docs/runtime-reference/examples/crm-01/contact.schema.json +1 -0
- package/sdk-dist/docs/runtime-reference/examples/crm-01/create-app.json +1 -0
- package/sdk-dist/docs/runtime-reference/examples/crm-01/customer.create-entity.json +1 -0
- package/sdk-dist/docs/runtime-reference/examples/crm-01/customer.schema.json +1 -0
- package/sdk-dist/docs/runtime-reference/examples/crm-01/follow-up.create-entity.json +1 -0
- package/sdk-dist/docs/runtime-reference/examples/crm-01/follow-up.schema.json +1 -0
- package/sdk-dist/docs/runtime-reference/examples/crm-01/lead.bulk-update.json +1 -0
- package/sdk-dist/docs/runtime-reference/examples/crm-01/lead.create-entity.json +1 -0
- package/sdk-dist/docs/runtime-reference/examples/crm-01/lead.query.json +1 -0
- package/sdk-dist/docs/runtime-reference/examples/crm-01/lead.row.insert.json +1 -0
- package/sdk-dist/docs/runtime-reference/examples/crm-01/lead.schema.json +1 -0
- package/sdk-dist/docs/runtime-reference/examples/crm-01/lead.selection.condition.json +1 -0
- package/sdk-dist/docs/runtime-reference/examples/oms-01/README.md +26 -26
- package/sdk-dist/docs/runtime-reference/examples/oms-01/sales-order.row.insert.json +1 -1
- package/sdk-dist/docs/runtime-reference/examples/wms-01/README.md +26 -10
- package/sdk-dist/docs/runtime-reference/examples/wms-01/create-app.json +1 -0
- package/sdk-dist/docs/runtime-reference/examples/wms-01/goods-receipt.create-entity.json +1 -0
- package/sdk-dist/docs/runtime-reference/examples/wms-01/goods-receipt.schema.json +1 -0
- package/sdk-dist/docs/runtime-reference/examples/wms-01/inventory-snapshot.bulk-update.json +1 -0
- package/sdk-dist/docs/runtime-reference/examples/wms-01/inventory-snapshot.create-entity.json +1 -0
- package/sdk-dist/docs/runtime-reference/examples/wms-01/inventory-snapshot.query.json +1 -0
- package/sdk-dist/docs/runtime-reference/examples/wms-01/inventory-snapshot.schema.json +1 -0
- package/sdk-dist/docs/runtime-reference/examples/wms-01/inventory-snapshot.selection.condition.json +1 -0
- package/sdk-dist/docs/runtime-reference/examples/wms-01/item-master.create-entity.json +1 -0
- package/sdk-dist/docs/runtime-reference/examples/wms-01/item-master.schema.json +1 -0
- package/sdk-dist/docs/runtime-reference/examples/wms-01/stock-issue.create-entity.json +1 -0
- package/sdk-dist/docs/runtime-reference/examples/wms-01/stock-issue.schema.json +1 -0
- package/sdk-dist/docs/runtime-reference/row-crud.md +35 -8
- package/sdk-dist/docs/runtime-reference/search-and-bulk-actions.md +31 -95
- package/sdk-dist/docs/runtime-reference/selection.md +128 -0
- package/sdk-dist/docs/runtime-reference/table-lifecycle.md +113 -30
- package/sdk-dist/docs/runtime-reference/uploads.md +30 -59
- package/sdk-dist/docs/runtime-reference/workflow/README.md +129 -13
- package/sdk-dist/generated/command_registry.generated.ts +37 -36
- package/sdk-dist/generated/type_index.generated.ts +23 -23
- package/src/generated/command_registry.generated.ts +37 -36
- package/src/generated/type_index.generated.ts +23 -23
- package/src/runtime/entity_save_schema.ts +30 -0
- package/src/runtime/env.ts +14 -2
- package/src/runtime/errors.ts +2 -0
- package/src/runtime/execute.ts +1166 -134
- package/src/runtime/paths.ts +11 -2
- package/src/runtime/upload.ts +19 -178
- package/src/runtime/zod_registry.ts +113 -48
- package/src/tests/bootstrap.test.ts +16 -0
- package/src/tests/command_registry.test.ts +9 -0
- package/src/tests/docs_readability.test.ts +96 -0
- package/src/tests/entity_save_schema.test.ts +22 -0
- package/src/tests/execute_validation.test.ts +508 -47
- package/src/tests/help.test.ts +49 -8
- package/src/tests/upload.test.ts +34 -91
package/dist/tests/help.test.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import test from 'node:test';
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
3
|
import { executeCLI } from '../runtime/execute.js';
|
|
4
|
+
import { listCommands } from '../runtime/command_registry.js';
|
|
5
|
+
import { getTypeHints } from '../runtime/zod_registry.js';
|
|
4
6
|
const env = {
|
|
5
7
|
ARCUBASE_BASE_URL: 'https://arcubase.example.com',
|
|
6
8
|
ARCUBASE_ACCESS_TOKEN: 'tok',
|
|
9
|
+
ARCUBASE_SDK_ROOT: '/runtime/arcubase-sdk',
|
|
7
10
|
ARCUBASE_TRACE_ID: '',
|
|
8
11
|
ARCUBASE_SUBJECT_TYPE: '',
|
|
9
12
|
ARCUBASE_SUBJECT_ID: '',
|
|
@@ -43,33 +46,67 @@ test('admin module help lists reset app commands', async () => {
|
|
|
43
46
|
assert.doesNotMatch(out.text, /create-entity/);
|
|
44
47
|
});
|
|
45
48
|
test('user row help replaces workflow row commands', async () => {
|
|
46
|
-
const out = await executeCLI('user', ['row', 'query', '--help'],
|
|
49
|
+
const out = await executeCLI('user', ['row', 'query', '--help'], env, async () => new Response('{}'));
|
|
47
50
|
assert.equal(out.kind, 'help');
|
|
48
|
-
assert.match(out.text, /body: .*--body-
|
|
51
|
+
assert.match(out.text, /body: .*--body-json <json-string> \| --body-file <file>\.json/);
|
|
49
52
|
assert.match(out.text, /query flags: --query-file/);
|
|
50
53
|
assert.doesNotMatch(out.text, /workflow query-entity/);
|
|
51
54
|
assert.doesNotMatch(out.text, /--entity-id/);
|
|
52
55
|
});
|
|
56
|
+
test('user row help does not expose internal policy id input', async () => {
|
|
57
|
+
const out = await executeCLI('user', ['row', 'get', '--help'], env, async () => new Response('{}'));
|
|
58
|
+
assert.equal(out.kind, 'help');
|
|
59
|
+
assert.doesNotMatch(out.text, /--policy-id/);
|
|
60
|
+
assert.doesNotMatch(out.text, /policy_id/);
|
|
61
|
+
});
|
|
53
62
|
test('admin table update-schema help uses table nouns and body-json', async () => {
|
|
54
|
-
const out = await executeCLI('admin', ['table', 'update-schema', '--help'],
|
|
63
|
+
const out = await executeCLI('admin', ['table', 'update-schema', '--help'], env, async () => new Response('{}'));
|
|
55
64
|
assert.equal(out.kind, 'help');
|
|
56
|
-
assert.match(out.text, /body: .*--body-
|
|
65
|
+
assert.match(out.text, /body: .*--body-json <json-string> \| --body-file <file>\.json/);
|
|
66
|
+
assert.match(out.text, /prefer --body-json/);
|
|
57
67
|
assert.match(out.text, /path flags: --app-id, --table-id/);
|
|
58
68
|
assert.doesNotMatch(out.text, /--entity-id/);
|
|
59
69
|
assert.doesNotMatch(out.text, /admin-save-entity/);
|
|
60
70
|
});
|
|
71
|
+
test('admin table create help gives one-call body-json example', async () => {
|
|
72
|
+
const out = await executeCLI('admin', ['table', 'create', '--help'], env, async () => new Response('{}'));
|
|
73
|
+
assert.equal(out.kind, 'help');
|
|
74
|
+
assert.match(out.text, /body-json example:/);
|
|
75
|
+
assert.match(out.text, /"field_id_seq":1003/);
|
|
76
|
+
assert.match(out.text, /"label":"投票描述"/);
|
|
77
|
+
assert.match(out.text, /"type":"textarea"/);
|
|
78
|
+
});
|
|
61
79
|
test('admin access-rule help gives update whitelist and assign-users body-json examples', async () => {
|
|
62
|
-
const
|
|
80
|
+
const create = await executeCLI('admin', ['access-rule', 'create', '--help'], env, async () => new Response('{}'));
|
|
81
|
+
assert.equal(create.kind, 'help');
|
|
82
|
+
assert.match(create.text, /Access rule/);
|
|
83
|
+
assert.match(create.text, /access-rule\.md/);
|
|
84
|
+
assert.match(create.text, /"user_scope":\[\{"type":"user","id":2188889901\}\]/);
|
|
85
|
+
assert.doesNotMatch(create.text, /"user_scope":\[\{"type":"member"/);
|
|
86
|
+
const update = await executeCLI('admin', ['access-rule', 'update', '--help'], env, async () => new Response('{}'));
|
|
63
87
|
assert.equal(update.kind, 'help');
|
|
64
88
|
assert.match(update.text, /--app-id/);
|
|
65
89
|
assert.match(update.text, /--table-id/);
|
|
66
90
|
assert.match(update.text, /--rule-id/);
|
|
67
91
|
assert.match(update.text, /"update":\["enabled"\]/);
|
|
68
|
-
|
|
92
|
+
assert.match(update.text, /"actions":\["view","add","edit"\]/);
|
|
93
|
+
const assign = await executeCLI('admin', ['access-rule', 'assign-users', '--help'], env, async () => new Response('{}'));
|
|
69
94
|
assert.equal(assign.kind, 'help');
|
|
70
95
|
assert.match(assign.text, /"update":\["user_scope"\]/);
|
|
71
|
-
assert.match(assign.text, /\{"update":\["user_scope"\],"options":\{"user_scope":\[\{"type":"
|
|
72
|
-
assert.doesNotMatch(assign.text, /"type":"
|
|
96
|
+
assert.match(assign.text, /\{"update":\["user_scope"\],"options":\{"user_scope":\[\{"type":"user","id":2188889901\}\]\}\}/);
|
|
97
|
+
assert.doesNotMatch(assign.text, /"type":"member"/);
|
|
73
98
|
assert.doesNotMatch(assign.text, /"users"/);
|
|
74
99
|
assert.doesNotMatch(assign.text, /"allowedUsers"/);
|
|
75
100
|
});
|
|
101
|
+
test('every body command help exposes readable TypeScript type paths', async () => {
|
|
102
|
+
for (const scope of ['admin', 'user']) {
|
|
103
|
+
for (const command of listCommands(scope).filter((item) => item.requestType)) {
|
|
104
|
+
const out = await executeCLI(scope, [...command.commandPath, '--help'], env, async () => new Response('{}'));
|
|
105
|
+
assert.equal(out.kind, 'help');
|
|
106
|
+
assert.match(out.text, /^types:$/m, `${scope} ${command.commandPath.join(' ')} must expose types section`);
|
|
107
|
+
for (const hint of getTypeHints(command.requestType ?? '', env)) {
|
|
108
|
+
assert.match(out.text, new RegExp(`${hint.symbol}: ${hint.file}`.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
});
|
|
@@ -1,106 +1,59 @@
|
|
|
1
1
|
import test from 'node:test';
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
|
-
import fs from 'fs';
|
|
4
|
-
import os from 'os';
|
|
5
|
-
import path from 'path';
|
|
6
3
|
import { executeCLI } from '../runtime/execute.js';
|
|
4
|
+
import { CLIError } from '../runtime/errors.js';
|
|
7
5
|
const env = {
|
|
8
6
|
ARCUBASE_BASE_URL: 'https://arcubase.example.com',
|
|
9
7
|
ARCUBASE_ACCESS_TOKEN: 'tok',
|
|
8
|
+
ARCUBASE_SDK_ROOT: '/runtime/arcubase-sdk',
|
|
10
9
|
ARCUBASE_TRACE_ID: '',
|
|
11
10
|
ARCUBASE_SUBJECT_TYPE: '',
|
|
12
11
|
ARCUBASE_SUBJECT_ID: '',
|
|
13
12
|
ARCUBASE_TOKEN_EXPIRES_AT: '',
|
|
14
13
|
};
|
|
15
|
-
test('upload help
|
|
16
|
-
const out = await executeCLI('user', ['upload', '--help'],
|
|
14
|
+
test('upload module help exposes reset upload commands with injected SDK root', async () => {
|
|
15
|
+
const out = await executeCLI('user', ['upload', '--help'], env, async () => new Response('{}'));
|
|
17
16
|
assert.equal(out.kind, 'help');
|
|
18
|
-
assert.match(out.text, /
|
|
19
|
-
assert.match(out.text, /
|
|
17
|
+
assert.match(out.text, /commands:/);
|
|
18
|
+
assert.match(out.text, /token/);
|
|
19
|
+
assert.match(out.text, /preview/);
|
|
20
|
+
assert.match(out.text, /mobile/);
|
|
21
|
+
assert.match(out.text, /check-mobile/);
|
|
22
|
+
assert.doesNotMatch(out.text, /<local-file>/);
|
|
20
23
|
});
|
|
21
|
-
test('upload
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
test('upload rejects local file shortcut', async () => {
|
|
25
|
+
await assert.rejects(async () => {
|
|
26
|
+
await executeCLI('user', ['upload', './contract.pdf'], env, async () => new Response('{}'));
|
|
27
|
+
}, (error) => {
|
|
28
|
+
assert.ok(error instanceof CLIError);
|
|
29
|
+
assert.equal(error.code, 'UNKNOWN_COMMAND');
|
|
30
|
+
assert.match(error.message, /unknown command: upload \.\/contract\.pdf/);
|
|
31
|
+
return true;
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
test('upload token executes the explicit API command', async () => {
|
|
25
35
|
const calls = [];
|
|
26
|
-
const result = await executeCLI('user', ['upload',
|
|
36
|
+
const result = await executeCLI('user', ['upload', 'token', '--body-json', '{"global":false}'], env, async (input, init) => {
|
|
27
37
|
const url = String(input);
|
|
28
|
-
calls.push({ url, method: init?.method });
|
|
38
|
+
calls.push({ url, method: init?.method, body: typeof init?.body === 'string' ? init.body : undefined });
|
|
29
39
|
if (url === 'https://arcubase.example.com/api/upload/token') {
|
|
30
40
|
return new Response(JSON.stringify({
|
|
31
41
|
data: {
|
|
32
42
|
id: 123456,
|
|
33
43
|
mode: 'aliyun-oss',
|
|
34
|
-
token_data: {
|
|
35
|
-
dir: 'upload/123456/',
|
|
36
|
-
policy: 'policy',
|
|
37
|
-
accessid: 'accessid',
|
|
38
|
-
signature: 'signature',
|
|
39
|
-
host: 'https://uploads.example.com',
|
|
40
|
-
},
|
|
44
|
+
token_data: { host: 'https://uploads.example.com' },
|
|
41
45
|
},
|
|
42
46
|
}), { status: 200, headers: { 'Content-Type': 'application/json' } });
|
|
43
47
|
}
|
|
44
|
-
if (url === 'https://uploads.example.com') {
|
|
45
|
-
return new Response('', { status: 200 });
|
|
46
|
-
}
|
|
47
48
|
throw new Error(`unexpected fetch url: ${url}`);
|
|
48
49
|
});
|
|
49
50
|
assert.equal(result.kind, 'result');
|
|
50
|
-
assert.deepEqual(calls, [
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
upload_id: 123456,
|
|
57
|
-
file: 'contract.pdf',
|
|
58
|
-
file_name: 'contract.pdf',
|
|
59
|
-
meta: {},
|
|
51
|
+
assert.deepEqual(calls, [{ url: 'https://arcubase.example.com/api/upload/token', method: 'POST', body: '{"global":false}' }]);
|
|
52
|
+
assert.deepEqual(result.data, {
|
|
53
|
+
data: {
|
|
54
|
+
id: 123456,
|
|
55
|
+
mode: 'aliyun-oss',
|
|
56
|
+
token_data: { host: 'https://uploads.example.com' },
|
|
60
57
|
},
|
|
61
|
-
]);
|
|
62
|
-
});
|
|
63
|
-
test('upload supports s3-post-policy tokens', async () => {
|
|
64
|
-
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'arcubase-upload-s3-'));
|
|
65
|
-
const sourceFile = path.join(tempDir, 'contract.pdf');
|
|
66
|
-
fs.writeFileSync(sourceFile, 'fake pdf bytes');
|
|
67
|
-
const calls = [];
|
|
68
|
-
const result = await executeCLI('user', ['upload', sourceFile], env, async (input, init) => {
|
|
69
|
-
const url = String(input);
|
|
70
|
-
calls.push({ url, method: init?.method });
|
|
71
|
-
if (url === 'https://arcubase.example.com/api/upload/token') {
|
|
72
|
-
return new Response(JSON.stringify({
|
|
73
|
-
data: {
|
|
74
|
-
id: 654321,
|
|
75
|
-
mode: 's3-post-policy',
|
|
76
|
-
token_data: {
|
|
77
|
-
dir: 'upload/654321/',
|
|
78
|
-
policy: 'policy',
|
|
79
|
-
host: 'https://uploads.example.com/private-bucket',
|
|
80
|
-
x_amz_algorithm: 'AWS4-HMAC-SHA256',
|
|
81
|
-
x_amz_credential: 'test/20260504/us-east-1/s3/aws4_request',
|
|
82
|
-
x_amz_date: '20260504T010203Z',
|
|
83
|
-
x_amz_signature: 'abc123',
|
|
84
|
-
},
|
|
85
|
-
},
|
|
86
|
-
}), { status: 200, headers: { 'Content-Type': 'application/json' } });
|
|
87
|
-
}
|
|
88
|
-
if (url === 'https://uploads.example.com/private-bucket') {
|
|
89
|
-
return new Response('', { status: 200 });
|
|
90
|
-
}
|
|
91
|
-
throw new Error(`unexpected fetch url: ${url}`);
|
|
92
58
|
});
|
|
93
|
-
assert.equal(result.kind, 'result');
|
|
94
|
-
assert.deepEqual(calls, [
|
|
95
|
-
{ url: 'https://arcubase.example.com/api/upload/token', method: 'POST' },
|
|
96
|
-
{ url: 'https://uploads.example.com/private-bucket', method: 'POST' },
|
|
97
|
-
]);
|
|
98
|
-
assert.deepEqual(result.data, [
|
|
99
|
-
{
|
|
100
|
-
upload_id: 654321,
|
|
101
|
-
file: 'contract.pdf',
|
|
102
|
-
file_name: 'contract.pdf',
|
|
103
|
-
meta: {},
|
|
104
|
-
},
|
|
105
|
-
]);
|
|
106
59
|
});
|
package/package.json
CHANGED
|
@@ -11,13 +11,14 @@ Read it as a command cheatsheet:
|
|
|
11
11
|
- what result shape to expect
|
|
12
12
|
|
|
13
13
|
Do not start from raw HTTP methods or paths. Start from the CLI command.
|
|
14
|
+
Prefer `--body-json <json-string>` for normal payloads, including table schema, to avoid an extra agent file operation. Use `--body-file <file>.json` only when the JSON is too large for one tool call.
|
|
14
15
|
|
|
15
16
|
## Paths
|
|
16
17
|
|
|
17
18
|
- Development source:
|
|
18
19
|
- `misc/packages/@carthooks/arcubase-cli/docs/runtime-reference/`
|
|
19
20
|
- Runtime location:
|
|
20
|
-
-
|
|
21
|
+
- `$ARCUBASE_SDK_ROOT/docs/runtime-reference/`
|
|
21
22
|
- Published path:
|
|
22
23
|
- `sdk-dist/docs/runtime-reference/`
|
|
23
24
|
|
|
@@ -26,18 +27,18 @@ Do not start from raw HTTP methods or paths. Start from the CLI command.
|
|
|
26
27
|
Use `arcubase-admin` for:
|
|
27
28
|
|
|
28
29
|
- app creation
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
30
|
+
- table shell creation
|
|
31
|
+
- table schema save
|
|
32
|
+
- access-rule and workflow setup
|
|
32
33
|
|
|
33
34
|
Common commands:
|
|
34
35
|
|
|
35
36
|
```bash
|
|
36
|
-
arcubase-admin app create
|
|
37
|
-
arcubase-admin
|
|
38
|
-
arcubase-admin
|
|
39
|
-
arcubase-admin
|
|
40
|
-
arcubase-admin
|
|
37
|
+
arcubase-admin app create --body-file create-app.json | --body-json <json-string>
|
|
38
|
+
arcubase-admin table create --app-id <app_id> --body-json <json-string> | --body-file table-create.json
|
|
39
|
+
arcubase-admin table get --app-id <app_id> --table-id <table_id>
|
|
40
|
+
arcubase-admin table update-schema --app-id <app_id> --table-id <table_id> --body-json <json-string> | --body-file table-schema.json
|
|
41
|
+
arcubase-admin access-rule assign-users --app-id <app_id> --table-id <table_id> --rule-id <rule_id> --body-json <json-string> | --body-file assign-users.json
|
|
41
42
|
```
|
|
42
43
|
|
|
43
44
|
Use `arcubase` for:
|
|
@@ -49,31 +50,31 @@ Use `arcubase` for:
|
|
|
49
50
|
- search
|
|
50
51
|
- selection actions
|
|
51
52
|
- bulk update
|
|
52
|
-
- batch operator
|
|
53
53
|
|
|
54
54
|
Common commands:
|
|
55
55
|
|
|
56
56
|
```bash
|
|
57
|
-
arcubase row create --app-id <app_id> --table-id <table_id> --body-file insert.json
|
|
58
|
-
arcubase row query --app-id <app_id> --table-id <table_id> --body-file query.json
|
|
59
|
-
arcubase row update --app-id <app_id> --table-id <table_id> --row-id <row_id> --body-file update.json
|
|
60
|
-
arcubase row delete --app-id <app_id> --table-id <table_id> --body-file delete.json
|
|
61
|
-
arcubase row
|
|
62
|
-
arcubase row
|
|
57
|
+
arcubase row create --app-id <app_id> --table-id <table_id> --body-file insert.json | --body-json <json-string>
|
|
58
|
+
arcubase row query --app-id <app_id> --table-id <table_id> --body-file query.json | --body-json <json-string>
|
|
59
|
+
arcubase row update --app-id <app_id> --table-id <table_id> --row-id <row_id> --body-file update.json | --body-json <json-string>
|
|
60
|
+
arcubase row delete --app-id <app_id> --table-id <table_id> --body-file delete.json | --body-json <json-string>
|
|
61
|
+
arcubase row update --app-id <app_id> --table-id <table_id> --body-file restore.json | --body-json <json-string>
|
|
62
|
+
arcubase row selection-action --app-id <app_id> --table-id <table_id> --action archive --body-file selection.json | --body-json <json-string>
|
|
63
|
+
arcubase row bulk-update --app-id <app_id> --table-id <table_id> --body-file bulk-update.json | --body-json <json-string>
|
|
63
64
|
```
|
|
64
65
|
|
|
65
66
|
Hard rule:
|
|
66
67
|
|
|
68
|
+
- `table create` must include non-empty `fields`; empty table shell creation is not allowed
|
|
67
69
|
- `arcubase-admin` stops at schema save
|
|
68
70
|
- all row operations must switch to `arcubase`
|
|
69
|
-
- do not use `arcubase-admin row create`
|
|
70
71
|
- do not use `arcubase-admin row query`
|
|
71
72
|
|
|
72
73
|
## Required file inputs
|
|
73
74
|
|
|
74
75
|
Most write commands use:
|
|
75
76
|
|
|
76
|
-
- `--body-file <file>.json`
|
|
77
|
+
- `--body-file <file>.json` or `--body-json <json-string>`
|
|
77
78
|
|
|
78
79
|
Some query commands also use:
|
|
79
80
|
|
|
@@ -88,7 +89,7 @@ arcubase row query \
|
|
|
88
89
|
--app-id <app_id> \
|
|
89
90
|
--table-id <table_id> \
|
|
90
91
|
--query-file archived-query.json \
|
|
91
|
-
--body-file archived-body.json
|
|
92
|
+
--body-file archived-body.json | --body-json <json-string>
|
|
92
93
|
```
|
|
93
94
|
|
|
94
95
|
## Runtime env
|
|
@@ -97,6 +98,8 @@ The CLIs accept either generic env keys:
|
|
|
97
98
|
|
|
98
99
|
- `ARCUBASE_BASE_URL`
|
|
99
100
|
- `ARCUBASE_ACCESS_TOKEN`
|
|
101
|
+
- `ARCUBASE_SDK_ROOT`
|
|
102
|
+
- optional: `ARCUBASE_TRACE_ID`
|
|
100
103
|
|
|
101
104
|
or scoped env keys:
|
|
102
105
|
|
|
@@ -107,6 +110,9 @@ or scoped env keys:
|
|
|
107
110
|
- `ARCUBASE_USER_BASE_URL`
|
|
108
111
|
- `ARCUBASE_USER_ACCESS_TOKEN`
|
|
109
112
|
|
|
113
|
+
Tenant identity comes from the JWT access token. Do not pass tenant ids through CLI env.
|
|
114
|
+
- `ARCUBASE_USER_HOST`
|
|
115
|
+
|
|
110
116
|
Help should work without runtime env:
|
|
111
117
|
|
|
112
118
|
```bash
|
|
@@ -118,7 +124,7 @@ arcubase <module> --help
|
|
|
118
124
|
arcubase <module> <command> --help
|
|
119
125
|
```
|
|
120
126
|
|
|
121
|
-
Command help is also the
|
|
127
|
+
Command help is also the index entrypoint for this doc set.
|
|
122
128
|
|
|
123
129
|
When a command is tied to a common task, `--help` should print:
|
|
124
130
|
|
|
@@ -149,10 +155,17 @@ If you need a business-shaped template:
|
|
|
149
155
|
2. pick the closest domain directory
|
|
150
156
|
3. copy and adapt the example schema and payload files
|
|
151
157
|
|
|
152
|
-
If you need search, selection,
|
|
158
|
+
If you need search, selection, or bulk update:
|
|
153
159
|
|
|
154
160
|
1. read `search-and-bulk-actions.md`
|
|
155
|
-
2.
|
|
161
|
+
2. read `selection.md`
|
|
162
|
+
3. read `condition.md`
|
|
163
|
+
4. use `row-crud.md` only for row result shapes
|
|
164
|
+
|
|
165
|
+
If you need workflow actions:
|
|
166
|
+
|
|
167
|
+
1. read `workflow/README.md`
|
|
168
|
+
2. use the exact `task_id`, node, record, and user ids returned by Arcubase
|
|
156
169
|
|
|
157
170
|
## Covered now
|
|
158
171
|
|
|
@@ -167,13 +180,14 @@ If you need search, selection, tags, bulk update, or batch operator:
|
|
|
167
180
|
- `row-crud.md`
|
|
168
181
|
- insert, query, update, delete, restore
|
|
169
182
|
- `uploads.md`
|
|
170
|
-
- upload
|
|
183
|
+
- upload token, preview, mobile upload, and mobile upload check API payloads
|
|
171
184
|
- `search-and-bulk-actions.md`
|
|
172
|
-
- search, selection,
|
|
185
|
+
- search, selection, bulk update
|
|
186
|
+
- `selection.md`
|
|
187
|
+
- `EntitySelectionVO`, ids/all/condition selection, command action matrix
|
|
188
|
+
- `condition.md`
|
|
189
|
+
- selection condition, `FilterCond`, and `ConditionSet` differences
|
|
190
|
+
- `workflow/README.md`
|
|
191
|
+
- process map, approve, rollback, countersign, forward, retract, resolve, approver query, node query
|
|
173
192
|
- `examples/`
|
|
174
193
|
- business-shaped schema and payload templates
|
|
175
|
-
|
|
176
|
-
## Reserved expansion
|
|
177
|
-
|
|
178
|
-
- `workflow/README.md`
|
|
179
|
-
- reserved for future workflow-specific CLI docs
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Access Rule
|
|
2
|
+
|
|
3
|
+
Use `arcubase-admin access-rule` for app/table access.
|
|
4
|
+
|
|
5
|
+
## One Path
|
|
6
|
+
|
|
7
|
+
1. Get the numeric `TenantUser.ID`.
|
|
8
|
+
2. Create an enabled rule with `options.policy`.
|
|
9
|
+
3. Assign users with `options.user_scope`.
|
|
10
|
+
4. Verify with `access-rule get`.
|
|
11
|
+
|
|
12
|
+
## User Mapping
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
arcubase-admin get-digiemployee-users
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Use the numeric `tenantUserId` / `TenantUser.ID`.
|
|
19
|
+
|
|
20
|
+
Do not use hash ids such as `arcubaseTenantUserId`.
|
|
21
|
+
Use `user_scope[].type:"user"` for a tenant user. Do not use FieldVO field type `member` in access rules.
|
|
22
|
+
|
|
23
|
+
## Create Read/Write Rule With Hidden Field
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
arcubase-admin access-rule create \
|
|
27
|
+
--app-id 2188893436 \
|
|
28
|
+
--table-id 2188893443 \
|
|
29
|
+
--body-json '{"name":"Sales read write","enabled":true,"type":"form","options":{"user_scope":[{"type":"user","id":2188889901}],"policy":{"key":"custom","actions":["view","add","edit"],"all_fields_read":false,"all_fields_write":false,"fields":[{"key":":1001","read":true,"write":true,"report":false},{"key":":1002","read":false,"write":false,"report":false},{"key":":1003","read":true,"write":true,"report":false}]},"list_options":{}}}'
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Rules:
|
|
33
|
+
|
|
34
|
+
- read permission = `actions:["view"]`
|
|
35
|
+
- write permission = add `add` and `edit`
|
|
36
|
+
- field key is `":<field_id>"`, not a number
|
|
37
|
+
- field key is not the FieldVO `key`; do not use values like `vote_description`
|
|
38
|
+
- hidden field = `{"key":":1002","read":false,"write":false,"report":false}`
|
|
39
|
+
- when `all_fields_read=false` or `all_fields_write=false`, list each visible field with `read/write=true`
|
|
40
|
+
- do not use `permissions`
|
|
41
|
+
- do not use `field_visibility`
|
|
42
|
+
- do not use `actions:["read","insert"]`
|
|
43
|
+
|
|
44
|
+
## Enable Rule
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
arcubase-admin access-rule update \
|
|
48
|
+
--app-id 2188893436 \
|
|
49
|
+
--table-id 2188893443 \
|
|
50
|
+
--rule-id 2188893557 \
|
|
51
|
+
--body-json '{"update":["enabled"],"enabled":true}'
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Update Policy With Hidden Field
|
|
55
|
+
|
|
56
|
+
Use this when the rule already exists and the field visibility or actions must change.
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
arcubase-admin access-rule update \
|
|
60
|
+
--app-id 2188893436 \
|
|
61
|
+
--table-id 2188893443 \
|
|
62
|
+
--rule-id 2188893557 \
|
|
63
|
+
--body-json '{"update":["options"],"options":{"policy":{"key":"custom","actions":["view","add","edit"],"all_fields_read":false,"all_fields_write":false,"fields":[{"key":":1001","read":true,"write":true,"report":false},{"key":":1002","read":false,"write":false,"report":false},{"key":":1003","read":true,"write":true,"report":false}]},"list_options":{}}}'
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Rules:
|
|
67
|
+
|
|
68
|
+
- use `update:["options"]`
|
|
69
|
+
- do not use `update:["options.policy"]`
|
|
70
|
+
- field key is `":<field_id>"`, not a number
|
|
71
|
+
- field key is not the FieldVO `key`; do not use values like `vote_description`
|
|
72
|
+
- preserve `list_options:{}` unless the existing rule has a known replacement
|
|
73
|
+
|
|
74
|
+
## Assign Users Only
|
|
75
|
+
|
|
76
|
+
Use this only when the rule already has the correct `policy`.
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
arcubase-admin access-rule assign-users \
|
|
80
|
+
--app-id 2188893436 \
|
|
81
|
+
--table-id 2188893443 \
|
|
82
|
+
--rule-id 2188893557 \
|
|
83
|
+
--body-json '{"update":["user_scope"],"options":{"user_scope":[{"type":"user","id":2188889901}]}}'
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Rules:
|
|
87
|
+
|
|
88
|
+
- `assign-users` preserves the existing policy.
|
|
89
|
+
- body must use `update:["user_scope"]`.
|
|
90
|
+
- body must use `options.user_scope`.
|
|
91
|
+
- `user_scope[].type` is `user` for tenant users.
|
|
92
|
+
- `user_scope[].id` is numeric `TenantUser.ID`.
|
|
93
|
+
|
|
94
|
+
## Verify
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
arcubase-admin access-rule get \
|
|
98
|
+
--app-id 2188893436 \
|
|
99
|
+
--table-id 2188893443 \
|
|
100
|
+
--rule-id 2188893557
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Success:
|
|
104
|
+
|
|
105
|
+
- `enabled=true`
|
|
106
|
+
- `options.user_scope` contains the numeric user id
|
|
107
|
+
- `options.policy.actions` contains `view`, `add`, `edit`
|
|
108
|
+
- `options.policy.fields` contains hidden fields as `{"key":":1002","read":false,"write":false,"report":false}`
|
|
109
|
+
- visible fields are explicitly present with `read/write=true` when `all_fields_read/write=false`
|