@carthooks/arcubase-cli 0.1.10 → 0.1.13
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 +1365 -375
- package/bundle/arcubase.mjs +1365 -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 +3 -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 +1046 -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 +443 -44
- package/dist/tests/help.test.js +47 -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 +128 -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 +48 -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 +3 -0
- package/src/runtime/execute.ts +1272 -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 +577 -47
- package/src/tests/help.test.ts +51 -8
- package/src/tests/upload.test.ts +34 -91
|
@@ -78,10 +78,17 @@ function envValue(env, scope, key) {
|
|
|
78
78
|
function requiredValue(env, scope, key) {
|
|
79
79
|
const value = envValue(env, scope, key);
|
|
80
80
|
if (!value || value.trim() === "") {
|
|
81
|
-
throw new
|
|
81
|
+
throw new CLIError("RUNTIME_ENV_REQUIRED", `${key} is required`, 2);
|
|
82
82
|
}
|
|
83
83
|
return value;
|
|
84
84
|
}
|
|
85
|
+
function requiredDirectValue(env, key) {
|
|
86
|
+
const value = env[key];
|
|
87
|
+
if (!value || value.trim() === "") {
|
|
88
|
+
throw new CLIError("RUNTIME_ENV_REQUIRED", `${key} is required`, 2);
|
|
89
|
+
}
|
|
90
|
+
return value.trim();
|
|
91
|
+
}
|
|
85
92
|
function optionalValue(env, scope, key) {
|
|
86
93
|
const value = envValue(env, scope, key);
|
|
87
94
|
if (!value || value.trim() === "") {
|
|
@@ -93,6 +100,7 @@ function loadRuntimeEnv(scope, env = process.env) {
|
|
|
93
100
|
return {
|
|
94
101
|
ARCUBASE_BASE_URL: requiredValue(env, scope, "ARCUBASE_BASE_URL"),
|
|
95
102
|
ARCUBASE_ACCESS_TOKEN: requiredValue(env, scope, "ARCUBASE_ACCESS_TOKEN"),
|
|
103
|
+
ARCUBASE_SDK_ROOT: requiredDirectValue(env, "ARCUBASE_SDK_ROOT"),
|
|
96
104
|
ARCUBASE_TRACE_ID: optionalValue(env, scope, "ARCUBASE_TRACE_ID"),
|
|
97
105
|
ARCUBASE_SUBJECT_TYPE: optionalValue(env, scope, "ARCUBASE_SUBJECT_TYPE"),
|
|
98
106
|
ARCUBASE_SUBJECT_ID: optionalValue(env, scope, "ARCUBASE_SUBJECT_ID"),
|
|
@@ -151,7 +159,7 @@ var adminCommands = [
|
|
|
151
159
|
},
|
|
152
160
|
{
|
|
153
161
|
"scope": "admin",
|
|
154
|
-
"module": "
|
|
162
|
+
"module": "app",
|
|
155
163
|
"functionName": "getAppDetail",
|
|
156
164
|
"commandPath": [
|
|
157
165
|
"app",
|
|
@@ -230,7 +238,7 @@ var adminCommands = [
|
|
|
230
238
|
},
|
|
231
239
|
{
|
|
232
240
|
"scope": "admin",
|
|
233
|
-
"module": "
|
|
241
|
+
"module": "table",
|
|
234
242
|
"functionName": "getEntities",
|
|
235
243
|
"commandPath": [
|
|
236
244
|
"table",
|
|
@@ -251,7 +259,7 @@ var adminCommands = [
|
|
|
251
259
|
},
|
|
252
260
|
{
|
|
253
261
|
"scope": "admin",
|
|
254
|
-
"module": "
|
|
262
|
+
"module": "table",
|
|
255
263
|
"functionName": "adminGetEntityInfo",
|
|
256
264
|
"commandPath": [
|
|
257
265
|
"table",
|
|
@@ -276,7 +284,7 @@ var adminCommands = [
|
|
|
276
284
|
},
|
|
277
285
|
{
|
|
278
286
|
"scope": "admin",
|
|
279
|
-
"module": "
|
|
287
|
+
"module": "table",
|
|
280
288
|
"functionName": "createEntity",
|
|
281
289
|
"commandPath": [
|
|
282
290
|
"table",
|
|
@@ -297,7 +305,7 @@ var adminCommands = [
|
|
|
297
305
|
},
|
|
298
306
|
{
|
|
299
307
|
"scope": "admin",
|
|
300
|
-
"module": "
|
|
308
|
+
"module": "table",
|
|
301
309
|
"functionName": "adminSaveEntity",
|
|
302
310
|
"commandPath": [
|
|
303
311
|
"table",
|
|
@@ -322,7 +330,7 @@ var adminCommands = [
|
|
|
322
330
|
},
|
|
323
331
|
{
|
|
324
332
|
"scope": "admin",
|
|
325
|
-
"module": "
|
|
333
|
+
"module": "table",
|
|
326
334
|
"functionName": "adminSaveEntityName",
|
|
327
335
|
"commandPath": [
|
|
328
336
|
"table",
|
|
@@ -347,7 +355,7 @@ var adminCommands = [
|
|
|
347
355
|
},
|
|
348
356
|
{
|
|
349
357
|
"scope": "admin",
|
|
350
|
-
"module": "
|
|
358
|
+
"module": "table",
|
|
351
359
|
"functionName": "adminDeleteEntity",
|
|
352
360
|
"commandPath": [
|
|
353
361
|
"table",
|
|
@@ -372,7 +380,7 @@ var adminCommands = [
|
|
|
372
380
|
},
|
|
373
381
|
{
|
|
374
382
|
"scope": "admin",
|
|
375
|
-
"module": "
|
|
383
|
+
"module": "access-rule",
|
|
376
384
|
"functionName": "getEntityIngressList",
|
|
377
385
|
"commandPath": [
|
|
378
386
|
"access-rule",
|
|
@@ -397,7 +405,7 @@ var adminCommands = [
|
|
|
397
405
|
},
|
|
398
406
|
{
|
|
399
407
|
"scope": "admin",
|
|
400
|
-
"module": "
|
|
408
|
+
"module": "access-rule",
|
|
401
409
|
"functionName": "getEntityIngress",
|
|
402
410
|
"commandPath": [
|
|
403
411
|
"access-rule",
|
|
@@ -426,7 +434,7 @@ var adminCommands = [
|
|
|
426
434
|
},
|
|
427
435
|
{
|
|
428
436
|
"scope": "admin",
|
|
429
|
-
"module": "
|
|
437
|
+
"module": "access-rule",
|
|
430
438
|
"functionName": "createEntityIngress",
|
|
431
439
|
"commandPath": [
|
|
432
440
|
"access-rule",
|
|
@@ -451,7 +459,7 @@ var adminCommands = [
|
|
|
451
459
|
},
|
|
452
460
|
{
|
|
453
461
|
"scope": "admin",
|
|
454
|
-
"module": "
|
|
462
|
+
"module": "access-rule",
|
|
455
463
|
"functionName": "updateEntityIngress",
|
|
456
464
|
"commandPath": [
|
|
457
465
|
"access-rule",
|
|
@@ -480,7 +488,7 @@ var adminCommands = [
|
|
|
480
488
|
},
|
|
481
489
|
{
|
|
482
490
|
"scope": "admin",
|
|
483
|
-
"module": "
|
|
491
|
+
"module": "access-rule",
|
|
484
492
|
"functionName": "deleteEntityIngress",
|
|
485
493
|
"commandPath": [
|
|
486
494
|
"access-rule",
|
|
@@ -509,7 +517,7 @@ var adminCommands = [
|
|
|
509
517
|
},
|
|
510
518
|
{
|
|
511
519
|
"scope": "admin",
|
|
512
|
-
"module": "
|
|
520
|
+
"module": "access-rule",
|
|
513
521
|
"functionName": "updateEntityIngress",
|
|
514
522
|
"commandPath": [
|
|
515
523
|
"access-rule",
|
|
@@ -647,7 +655,7 @@ var adminCommands = [
|
|
|
647
655
|
var userCommands = [
|
|
648
656
|
{
|
|
649
657
|
"scope": "user",
|
|
650
|
-
"module": "
|
|
658
|
+
"module": "entry",
|
|
651
659
|
"functionName": "getEntry",
|
|
652
660
|
"commandPath": [
|
|
653
661
|
"entry"
|
|
@@ -660,16 +668,17 @@ var userCommands = [
|
|
|
660
668
|
"queryParams": [
|
|
661
669
|
{
|
|
662
670
|
"key": "include_app_tables",
|
|
663
|
-
"flag": "
|
|
671
|
+
"flag": "",
|
|
664
672
|
"type": "boolean",
|
|
665
|
-
"hasDefault": true
|
|
673
|
+
"hasDefault": true,
|
|
674
|
+
"fixedValue": "true"
|
|
666
675
|
}
|
|
667
676
|
],
|
|
668
677
|
"responseType": "GlobalActionEntryRespVO"
|
|
669
678
|
},
|
|
670
679
|
{
|
|
671
680
|
"scope": "user",
|
|
672
|
-
"module": "
|
|
681
|
+
"module": "table",
|
|
673
682
|
"functionName": "getEntityInfo",
|
|
674
683
|
"commandPath": [
|
|
675
684
|
"table",
|
|
@@ -694,7 +703,7 @@ var userCommands = [
|
|
|
694
703
|
},
|
|
695
704
|
{
|
|
696
705
|
"scope": "user",
|
|
697
|
-
"module": "
|
|
706
|
+
"module": "table",
|
|
698
707
|
"functionName": "getDataset",
|
|
699
708
|
"commandPath": [
|
|
700
709
|
"table",
|
|
@@ -719,7 +728,7 @@ var userCommands = [
|
|
|
719
728
|
},
|
|
720
729
|
{
|
|
721
730
|
"scope": "user",
|
|
722
|
-
"module": "
|
|
731
|
+
"module": "table",
|
|
723
732
|
"functionName": "queryLinktoPickOptions",
|
|
724
733
|
"commandPath": [
|
|
725
734
|
"table",
|
|
@@ -744,7 +753,7 @@ var userCommands = [
|
|
|
744
753
|
},
|
|
745
754
|
{
|
|
746
755
|
"scope": "user",
|
|
747
|
-
"module": "
|
|
756
|
+
"module": "row",
|
|
748
757
|
"functionName": "queryEntity",
|
|
749
758
|
"commandPath": [
|
|
750
759
|
"row",
|
|
@@ -769,7 +778,7 @@ var userCommands = [
|
|
|
769
778
|
},
|
|
770
779
|
{
|
|
771
780
|
"scope": "user",
|
|
772
|
-
"module": "
|
|
781
|
+
"module": "row",
|
|
773
782
|
"functionName": "getEntityRow",
|
|
774
783
|
"commandPath": [
|
|
775
784
|
"row",
|
|
@@ -805,7 +814,7 @@ var userCommands = [
|
|
|
805
814
|
},
|
|
806
815
|
{
|
|
807
816
|
"scope": "user",
|
|
808
|
-
"module": "
|
|
817
|
+
"module": "row",
|
|
809
818
|
"functionName": "insertEntity",
|
|
810
819
|
"commandPath": [
|
|
811
820
|
"row",
|
|
@@ -830,7 +839,7 @@ var userCommands = [
|
|
|
830
839
|
},
|
|
831
840
|
{
|
|
832
841
|
"scope": "user",
|
|
833
|
-
"module": "
|
|
842
|
+
"module": "row",
|
|
834
843
|
"functionName": "updateEntityRow",
|
|
835
844
|
"commandPath": [
|
|
836
845
|
"row",
|
|
@@ -859,7 +868,7 @@ var userCommands = [
|
|
|
859
868
|
},
|
|
860
869
|
{
|
|
861
870
|
"scope": "user",
|
|
862
|
-
"module": "
|
|
871
|
+
"module": "row",
|
|
863
872
|
"functionName": "deleteEntityRow",
|
|
864
873
|
"commandPath": [
|
|
865
874
|
"row",
|
|
@@ -884,7 +893,7 @@ var userCommands = [
|
|
|
884
893
|
},
|
|
885
894
|
{
|
|
886
895
|
"scope": "user",
|
|
887
|
-
"module": "
|
|
896
|
+
"module": "row",
|
|
888
897
|
"functionName": "updateEntityBulk",
|
|
889
898
|
"commandPath": [
|
|
890
899
|
"row",
|
|
@@ -909,7 +918,7 @@ var userCommands = [
|
|
|
909
918
|
},
|
|
910
919
|
{
|
|
911
920
|
"scope": "user",
|
|
912
|
-
"module": "
|
|
921
|
+
"module": "row",
|
|
913
922
|
"functionName": "queryEntitySelection",
|
|
914
923
|
"commandPath": [
|
|
915
924
|
"row",
|
|
@@ -938,7 +947,7 @@ var userCommands = [
|
|
|
938
947
|
},
|
|
939
948
|
{
|
|
940
949
|
"scope": "user",
|
|
941
|
-
"module": "
|
|
950
|
+
"module": "upload",
|
|
942
951
|
"functionName": "getUploadToken",
|
|
943
952
|
"commandPath": [
|
|
944
953
|
"upload",
|
|
@@ -954,7 +963,7 @@ var userCommands = [
|
|
|
954
963
|
},
|
|
955
964
|
{
|
|
956
965
|
"scope": "user",
|
|
957
|
-
"module": "
|
|
966
|
+
"module": "upload",
|
|
958
967
|
"functionName": "uploadPreview",
|
|
959
968
|
"commandPath": [
|
|
960
969
|
"upload",
|
|
@@ -970,7 +979,7 @@ var userCommands = [
|
|
|
970
979
|
},
|
|
971
980
|
{
|
|
972
981
|
"scope": "user",
|
|
973
|
-
"module": "
|
|
982
|
+
"module": "upload",
|
|
974
983
|
"functionName": "mobileUpload",
|
|
975
984
|
"commandPath": [
|
|
976
985
|
"upload",
|
|
@@ -986,7 +995,7 @@ var userCommands = [
|
|
|
986
995
|
},
|
|
987
996
|
{
|
|
988
997
|
"scope": "user",
|
|
989
|
-
"module": "
|
|
998
|
+
"module": "upload",
|
|
990
999
|
"functionName": "checkMobileUpload",
|
|
991
1000
|
"commandPath": [
|
|
992
1001
|
"upload",
|
|
@@ -1034,7 +1043,7 @@ var userCommands = [
|
|
|
1034
1043
|
},
|
|
1035
1044
|
{
|
|
1036
1045
|
"scope": "user",
|
|
1037
|
-
"module": "
|
|
1046
|
+
"module": "workflow",
|
|
1038
1047
|
"functionName": "getEntityProcessMap",
|
|
1039
1048
|
"commandPath": [
|
|
1040
1049
|
"workflow",
|
|
@@ -1063,7 +1072,7 @@ var userCommands = [
|
|
|
1063
1072
|
},
|
|
1064
1073
|
{
|
|
1065
1074
|
"scope": "user",
|
|
1066
|
-
"module": "
|
|
1075
|
+
"module": "workflow",
|
|
1067
1076
|
"functionName": "doEntityAction",
|
|
1068
1077
|
"commandPath": [
|
|
1069
1078
|
"workflow",
|
|
@@ -1097,7 +1106,7 @@ var userCommands = [
|
|
|
1097
1106
|
},
|
|
1098
1107
|
{
|
|
1099
1108
|
"scope": "user",
|
|
1100
|
-
"module": "
|
|
1109
|
+
"module": "workflow",
|
|
1101
1110
|
"functionName": "doEntityAction",
|
|
1102
1111
|
"commandPath": [
|
|
1103
1112
|
"workflow",
|
|
@@ -1131,7 +1140,7 @@ var userCommands = [
|
|
|
1131
1140
|
},
|
|
1132
1141
|
{
|
|
1133
1142
|
"scope": "user",
|
|
1134
|
-
"module": "
|
|
1143
|
+
"module": "workflow",
|
|
1135
1144
|
"functionName": "doEntityAction",
|
|
1136
1145
|
"commandPath": [
|
|
1137
1146
|
"workflow",
|
|
@@ -1165,7 +1174,7 @@ var userCommands = [
|
|
|
1165
1174
|
},
|
|
1166
1175
|
{
|
|
1167
1176
|
"scope": "user",
|
|
1168
|
-
"module": "
|
|
1177
|
+
"module": "workflow",
|
|
1169
1178
|
"functionName": "doEntityAction",
|
|
1170
1179
|
"commandPath": [
|
|
1171
1180
|
"workflow",
|
|
@@ -1199,7 +1208,7 @@ var userCommands = [
|
|
|
1199
1208
|
},
|
|
1200
1209
|
{
|
|
1201
1210
|
"scope": "user",
|
|
1202
|
-
"module": "
|
|
1211
|
+
"module": "workflow",
|
|
1203
1212
|
"functionName": "doEntityAction",
|
|
1204
1213
|
"commandPath": [
|
|
1205
1214
|
"workflow",
|
|
@@ -1881,8 +1890,8 @@ function getErrorMap() {
|
|
|
1881
1890
|
|
|
1882
1891
|
// node_modules/zod/v3/helpers/parseUtil.js
|
|
1883
1892
|
var makeIssue = (params) => {
|
|
1884
|
-
const { data, path
|
|
1885
|
-
const fullPath = [...
|
|
1893
|
+
const { data, path, errorMaps, issueData } = params;
|
|
1894
|
+
const fullPath = [...path, ...issueData.path || []];
|
|
1886
1895
|
const fullIssue = {
|
|
1887
1896
|
...issueData,
|
|
1888
1897
|
path: fullPath
|
|
@@ -1998,11 +2007,11 @@ var errorUtil;
|
|
|
1998
2007
|
|
|
1999
2008
|
// node_modules/zod/v3/types.js
|
|
2000
2009
|
var ParseInputLazyPath = class {
|
|
2001
|
-
constructor(parent, value,
|
|
2010
|
+
constructor(parent, value, path, key) {
|
|
2002
2011
|
this._cachedPath = [];
|
|
2003
2012
|
this.parent = parent;
|
|
2004
2013
|
this.data = value;
|
|
2005
|
-
this._path =
|
|
2014
|
+
this._path = path;
|
|
2006
2015
|
this._key = key;
|
|
2007
2016
|
}
|
|
2008
2017
|
get path() {
|
|
@@ -5555,99 +5564,113 @@ var unsupportedBodySchemas = {};
|
|
|
5555
5564
|
// src/generated/type_index.generated.ts
|
|
5556
5565
|
var typeIndex = {
|
|
5557
5566
|
"AppCreateByTenantsReqVO": {
|
|
5558
|
-
"file": "
|
|
5567
|
+
"file": "types/app.ts",
|
|
5559
5568
|
"dependencies": []
|
|
5560
5569
|
},
|
|
5561
5570
|
"AppCreateEntityReqVO": {
|
|
5562
|
-
"file": "
|
|
5571
|
+
"file": "types/app.ts",
|
|
5563
5572
|
"dependencies": []
|
|
5564
5573
|
},
|
|
5565
5574
|
"AppIngressCreateReqVO": {
|
|
5566
|
-
"file": "
|
|
5575
|
+
"file": "types/ingress.ts",
|
|
5567
5576
|
"dependencies": []
|
|
5568
5577
|
},
|
|
5569
5578
|
"AppIngressUpdateReqVO": {
|
|
5570
|
-
"file": "
|
|
5579
|
+
"file": "types/ingress.ts",
|
|
5571
5580
|
"dependencies": []
|
|
5572
5581
|
},
|
|
5573
5582
|
"AppUpdateAppReqVO": {
|
|
5574
|
-
"file": "
|
|
5583
|
+
"file": "types/app.ts",
|
|
5575
5584
|
"dependencies": []
|
|
5576
5585
|
},
|
|
5577
5586
|
"EntityBulkUpdateReqVO": {
|
|
5578
|
-
"file": "
|
|
5587
|
+
"file": "types/user-action.ts",
|
|
5579
5588
|
"dependencies": []
|
|
5580
5589
|
},
|
|
5581
5590
|
"EntityDoActionReqVO": {
|
|
5582
|
-
"file": "
|
|
5591
|
+
"file": "types/user-action.ts",
|
|
5583
5592
|
"dependencies": []
|
|
5584
5593
|
},
|
|
5585
5594
|
"EntityQueryRelationReqVO": {
|
|
5586
|
-
"file": "
|
|
5595
|
+
"file": "types/user-action.ts",
|
|
5587
5596
|
"dependencies": []
|
|
5588
5597
|
},
|
|
5589
5598
|
"EntityQueryReqVO": {
|
|
5590
|
-
"file": "
|
|
5599
|
+
"file": "types/user-action.ts",
|
|
5591
5600
|
"dependencies": []
|
|
5592
5601
|
},
|
|
5593
5602
|
"EntityResolveWorkflowReqVO": {
|
|
5594
|
-
"file": "
|
|
5603
|
+
"file": "types/user-action.ts",
|
|
5595
5604
|
"dependencies": []
|
|
5596
5605
|
},
|
|
5597
5606
|
"EntitySaveNameReqVO": {
|
|
5598
|
-
"file": "
|
|
5607
|
+
"file": "types/entity.ts",
|
|
5599
5608
|
"dependencies": []
|
|
5600
5609
|
},
|
|
5601
5610
|
"EntitySaveReqVO": {
|
|
5602
|
-
"file": "
|
|
5611
|
+
"file": "types/entity.ts",
|
|
5603
5612
|
"dependencies": []
|
|
5604
5613
|
},
|
|
5605
5614
|
"EntitySelectionActionReqVO": {
|
|
5606
|
-
"file": "
|
|
5615
|
+
"file": "types/user-action.ts",
|
|
5607
5616
|
"dependencies": []
|
|
5608
5617
|
},
|
|
5609
5618
|
"EntityUpdateReqVO": {
|
|
5610
|
-
"file": "
|
|
5619
|
+
"file": "types/user-action.ts",
|
|
5611
5620
|
"dependencies": []
|
|
5612
5621
|
},
|
|
5613
5622
|
"EntityWorkflowApproveUsersReqVO": {
|
|
5614
|
-
"file": "
|
|
5623
|
+
"file": "types/user-action.ts",
|
|
5615
5624
|
"dependencies": []
|
|
5616
5625
|
},
|
|
5617
5626
|
"EntityWorkflowDeployReqVO": {
|
|
5618
|
-
"file": "
|
|
5627
|
+
"file": "types/workflow.ts",
|
|
5619
5628
|
"dependencies": []
|
|
5620
5629
|
},
|
|
5621
5630
|
"EntityWorkflowUpdateReqVO": {
|
|
5622
|
-
"file": "
|
|
5631
|
+
"file": "types/workflow.ts",
|
|
5623
5632
|
"dependencies": []
|
|
5624
5633
|
},
|
|
5625
5634
|
"GetUploadTokenReqVO": {
|
|
5626
|
-
"file": "
|
|
5635
|
+
"file": "types/user-action.ts",
|
|
5627
5636
|
"dependencies": []
|
|
5628
5637
|
},
|
|
5629
5638
|
"InsertReqVO": {
|
|
5630
|
-
"file": "
|
|
5639
|
+
"file": "types/user-action.ts",
|
|
5631
5640
|
"dependencies": []
|
|
5632
5641
|
},
|
|
5633
5642
|
"MobileUploadCheckReqVO": {
|
|
5634
|
-
"file": "
|
|
5643
|
+
"file": "types/user-action.ts",
|
|
5635
5644
|
"dependencies": []
|
|
5636
5645
|
},
|
|
5637
5646
|
"MobileUploadReqVO": {
|
|
5638
|
-
"file": "
|
|
5647
|
+
"file": "types/user-action.ts",
|
|
5639
5648
|
"dependencies": []
|
|
5640
5649
|
},
|
|
5641
5650
|
"UploadPreviewReqVO": {
|
|
5642
|
-
"file": "
|
|
5651
|
+
"file": "types/common.ts",
|
|
5643
5652
|
"dependencies": []
|
|
5644
5653
|
},
|
|
5645
5654
|
"UserProfileUpdateReqVO": {
|
|
5646
|
-
"file": "
|
|
5655
|
+
"file": "types/user-action.ts",
|
|
5647
5656
|
"dependencies": []
|
|
5648
5657
|
}
|
|
5649
5658
|
};
|
|
5650
5659
|
|
|
5660
|
+
// src/runtime/paths.ts
|
|
5661
|
+
function resolveArcubaseSDKRoot(env = process.env) {
|
|
5662
|
+
const value = env.ARCUBASE_SDK_ROOT?.trim();
|
|
5663
|
+
if (value) return value;
|
|
5664
|
+
throw new CLIError("RUNTIME_ENV_REQUIRED", "ARCUBASE_SDK_ROOT is required", 2);
|
|
5665
|
+
}
|
|
5666
|
+
function resolveArcubaseSDKPath(filePath, env = process.env) {
|
|
5667
|
+
const cleanPath = String(filePath || "").trim().replace(/^\/+/, "");
|
|
5668
|
+
if (!cleanPath) {
|
|
5669
|
+
throw new CLIError("RUNTIME_ENV_REQUIRED", "ARCUBASE_SDK_ROOT path is required", 2);
|
|
5670
|
+
}
|
|
5671
|
+
return `${resolveArcubaseSDKRoot(env).replace(/\/+$/, "")}/${cleanPath}`;
|
|
5672
|
+
}
|
|
5673
|
+
|
|
5651
5674
|
// src/runtime/entity_save_schema.ts
|
|
5652
5675
|
var simpleFieldTypes = [
|
|
5653
5676
|
"text",
|
|
@@ -5791,6 +5814,32 @@ function isRecord(value) {
|
|
|
5791
5814
|
function cloneJSON(value) {
|
|
5792
5815
|
return JSON.parse(JSON.stringify(value));
|
|
5793
5816
|
}
|
|
5817
|
+
function normalizeFieldVO(value) {
|
|
5818
|
+
if (!isRecord(value)) {
|
|
5819
|
+
return value;
|
|
5820
|
+
}
|
|
5821
|
+
const field = { ...value };
|
|
5822
|
+
field.unique ??= false;
|
|
5823
|
+
field.editable ??= true;
|
|
5824
|
+
field.visible ??= true;
|
|
5825
|
+
field.show_label ??= true;
|
|
5826
|
+
field.scannable ??= false;
|
|
5827
|
+
field.default_value_mode ??= 0;
|
|
5828
|
+
field.description ??= "";
|
|
5829
|
+
field.value ??= null;
|
|
5830
|
+
field.number_decimal ??= 0;
|
|
5831
|
+
field.depends ??= [];
|
|
5832
|
+
field.code_index ??= false;
|
|
5833
|
+
field.transfers ??= null;
|
|
5834
|
+
if (field.type === "subform") {
|
|
5835
|
+
if (Array.isArray(field.children)) {
|
|
5836
|
+
field.children = field.children.map((child) => normalizeFieldVO(child));
|
|
5837
|
+
}
|
|
5838
|
+
} else {
|
|
5839
|
+
field.children ??= null;
|
|
5840
|
+
}
|
|
5841
|
+
return field;
|
|
5842
|
+
}
|
|
5794
5843
|
function makeSimpleFieldSchema(type) {
|
|
5795
5844
|
return external_exports.object({
|
|
5796
5845
|
...fieldCommonShape,
|
|
@@ -5942,6 +5991,9 @@ function normalizeEntitySaveInput(value) {
|
|
|
5942
5991
|
}
|
|
5943
5992
|
}
|
|
5944
5993
|
}
|
|
5994
|
+
if (Array.isArray(entity.fields)) {
|
|
5995
|
+
entity.fields = entity.fields.map((field) => normalizeFieldVO(field));
|
|
5996
|
+
}
|
|
5945
5997
|
return entity;
|
|
5946
5998
|
}
|
|
5947
5999
|
function collectAllFieldIds(fields) {
|
|
@@ -6320,60 +6372,105 @@ function getUnsupportedBodySchemaReason(typeName) {
|
|
|
6320
6372
|
if (!name) return null;
|
|
6321
6373
|
return unsupportedBodySchemas[name] ?? null;
|
|
6322
6374
|
}
|
|
6375
|
+
function sdkPath(file, env = process.env) {
|
|
6376
|
+
return resolveArcubaseSDKPath(file.replace(/^\/?opt\/arcubase-sdk\/?/, ""), env);
|
|
6377
|
+
}
|
|
6378
|
+
function resolveTypeHintFiles(hints, env = process.env) {
|
|
6379
|
+
return hints.map((item) => ({ ...item, file: sdkPath(item.file, env) }));
|
|
6380
|
+
}
|
|
6381
|
+
function resolveDocHintFiles(hints, env = process.env) {
|
|
6382
|
+
return hints.map((item) => ({ ...item, file: sdkPath(item.file, env) }));
|
|
6383
|
+
}
|
|
6323
6384
|
var examplesIndexDocHint = {
|
|
6324
6385
|
title: "Examples index",
|
|
6325
|
-
file: "
|
|
6386
|
+
file: "docs/runtime-reference/examples/README.md"
|
|
6387
|
+
};
|
|
6388
|
+
var selectionDocHint = {
|
|
6389
|
+
title: "Selection",
|
|
6390
|
+
file: "docs/runtime-reference/selection.md"
|
|
6391
|
+
};
|
|
6392
|
+
var conditionDocHint = {
|
|
6393
|
+
title: "Condition",
|
|
6394
|
+
file: "docs/runtime-reference/condition.md"
|
|
6326
6395
|
};
|
|
6327
6396
|
var docHintIndex = {
|
|
6328
6397
|
AppCreateByTenantsReqVO: [
|
|
6329
|
-
{ title: "Table lifecycle", file: "
|
|
6398
|
+
{ title: "Table lifecycle", file: "docs/runtime-reference/table-lifecycle.md" },
|
|
6330
6399
|
examplesIndexDocHint
|
|
6331
6400
|
],
|
|
6332
6401
|
AppCreateEntityReqVO: [
|
|
6333
|
-
{ title: "Table lifecycle", file: "
|
|
6402
|
+
{ title: "Table lifecycle", file: "docs/runtime-reference/table-lifecycle.md" },
|
|
6403
|
+
{ title: "Table schema cheatsheet", file: "docs/runtime-reference/entity-schema.md" },
|
|
6404
|
+
{ title: "Field type index", file: "docs/runtime-reference/entity-schema/README.md" },
|
|
6405
|
+
examplesIndexDocHint
|
|
6406
|
+
],
|
|
6407
|
+
AppIngressCreateReqVO: [
|
|
6408
|
+
{ title: "Access rule", file: "docs/runtime-reference/access-rule.md" },
|
|
6409
|
+
examplesIndexDocHint
|
|
6410
|
+
],
|
|
6411
|
+
AppIngressUpdateReqVO: [
|
|
6412
|
+
{ title: "Access rule", file: "docs/runtime-reference/access-rule.md" },
|
|
6334
6413
|
examplesIndexDocHint
|
|
6335
6414
|
],
|
|
6336
6415
|
EntitySaveReqVO: [
|
|
6337
|
-
{ title: "
|
|
6416
|
+
{ title: "Table schema cheatsheet", file: "docs/runtime-reference/entity-schema.md" },
|
|
6417
|
+
{ title: "Field type index", file: "docs/runtime-reference/entity-schema/README.md" },
|
|
6418
|
+
{ title: "Text field", file: "docs/runtime-reference/entity-schema/text.md" },
|
|
6419
|
+
{ title: "Textarea field", file: "docs/runtime-reference/entity-schema/textarea.md" },
|
|
6420
|
+
{ title: "Number field", file: "docs/runtime-reference/entity-schema/number.md" },
|
|
6421
|
+
{ title: "Datetime field", file: "docs/runtime-reference/entity-schema/datetime.md" },
|
|
6422
|
+
{ title: "Boolean field", file: "docs/runtime-reference/entity-schema/boolean.md" },
|
|
6423
|
+
{ title: "Select field", file: "docs/runtime-reference/entity-schema/select.md" },
|
|
6338
6424
|
examplesIndexDocHint
|
|
6339
6425
|
],
|
|
6340
6426
|
EntityQueryReqVO: [
|
|
6341
|
-
{ title: "Row CRUD", file: "
|
|
6342
|
-
{ title: "Search and bulk actions", file: "
|
|
6427
|
+
{ title: "Row CRUD", file: "docs/runtime-reference/row-crud.md" },
|
|
6428
|
+
{ title: "Search and bulk actions", file: "docs/runtime-reference/search-and-bulk-actions.md" },
|
|
6429
|
+
conditionDocHint,
|
|
6343
6430
|
examplesIndexDocHint
|
|
6344
6431
|
],
|
|
6345
6432
|
EntityUpdateReqVO: [
|
|
6346
|
-
{ title: "Row CRUD", file: "
|
|
6347
|
-
{ title: "Uploads", file: "
|
|
6433
|
+
{ title: "Row CRUD", file: "docs/runtime-reference/row-crud.md" },
|
|
6434
|
+
{ title: "Uploads", file: "docs/runtime-reference/uploads.md" },
|
|
6348
6435
|
examplesIndexDocHint
|
|
6349
6436
|
],
|
|
6350
6437
|
EntitySelectionActionReqVO: [
|
|
6351
|
-
|
|
6438
|
+
selectionDocHint,
|
|
6439
|
+
conditionDocHint,
|
|
6440
|
+
{ title: "Search and bulk actions", file: "docs/runtime-reference/search-and-bulk-actions.md" },
|
|
6352
6441
|
examplesIndexDocHint
|
|
6353
6442
|
],
|
|
6354
6443
|
InsertReqVO: [
|
|
6355
|
-
{ title: "Row CRUD", file: "
|
|
6356
|
-
{ title: "Uploads", file: "
|
|
6444
|
+
{ title: "Row CRUD", file: "docs/runtime-reference/row-crud.md" },
|
|
6445
|
+
{ title: "Uploads", file: "docs/runtime-reference/uploads.md" },
|
|
6357
6446
|
examplesIndexDocHint
|
|
6358
6447
|
],
|
|
6359
6448
|
EntityBulkUpdateReqVO: [
|
|
6360
|
-
|
|
6449
|
+
selectionDocHint,
|
|
6450
|
+
conditionDocHint,
|
|
6451
|
+
{ title: "Search and bulk actions", file: "docs/runtime-reference/search-and-bulk-actions.md" },
|
|
6361
6452
|
examplesIndexDocHint
|
|
6362
6453
|
],
|
|
6363
6454
|
"EntityInvokeBatchOperatorReqVO & InvokeRequestVO": [
|
|
6364
|
-
|
|
6455
|
+
selectionDocHint,
|
|
6456
|
+
conditionDocHint,
|
|
6457
|
+
{ title: "Search and bulk actions", file: "docs/runtime-reference/search-and-bulk-actions.md" },
|
|
6365
6458
|
examplesIndexDocHint
|
|
6366
6459
|
],
|
|
6367
6460
|
"{ policy_id: string selection: any }": [
|
|
6368
|
-
|
|
6461
|
+
selectionDocHint,
|
|
6462
|
+
conditionDocHint,
|
|
6463
|
+
{ title: "Search and bulk actions", file: "docs/runtime-reference/search-and-bulk-actions.md" },
|
|
6369
6464
|
examplesIndexDocHint
|
|
6370
6465
|
],
|
|
6371
6466
|
"{ policy_id: string selection: any tag_names: string[] }": [
|
|
6372
|
-
|
|
6467
|
+
selectionDocHint,
|
|
6468
|
+
conditionDocHint,
|
|
6469
|
+
{ title: "Search and bulk actions", file: "docs/runtime-reference/search-and-bulk-actions.md" },
|
|
6373
6470
|
examplesIndexDocHint
|
|
6374
6471
|
]
|
|
6375
6472
|
};
|
|
6376
|
-
function getTypeHints(typeName) {
|
|
6473
|
+
function getTypeHints(typeName, env = process.env) {
|
|
6377
6474
|
const name = String(typeName || "").trim();
|
|
6378
6475
|
if (!name) return [];
|
|
6379
6476
|
const entry = typeIndex[name];
|
|
@@ -6393,211 +6490,86 @@ function getTypeHints(typeName) {
|
|
|
6393
6490
|
for (const dep of entry.dependencies ?? []) {
|
|
6394
6491
|
append(dep.symbol, dep.file);
|
|
6395
6492
|
}
|
|
6396
|
-
return out;
|
|
6493
|
+
return resolveTypeHintFiles(out, env);
|
|
6397
6494
|
}
|
|
6398
|
-
function getDocHints(typeName) {
|
|
6495
|
+
function getDocHints(typeName, env = process.env) {
|
|
6399
6496
|
const name = String(typeName || "").trim();
|
|
6400
6497
|
if (!name) return [];
|
|
6401
|
-
return docHintIndex[name] ?? [];
|
|
6498
|
+
return resolveDocHintFiles(docHintIndex[name] ?? [], env);
|
|
6402
6499
|
}
|
|
6403
6500
|
var commandDocHintIndex = {
|
|
6404
6501
|
"admin.app.createAppByTenants": [
|
|
6405
|
-
{ title: "Table lifecycle", file: "
|
|
6502
|
+
{ title: "Table lifecycle", file: "docs/runtime-reference/table-lifecycle.md" },
|
|
6406
6503
|
examplesIndexDocHint
|
|
6407
6504
|
],
|
|
6408
6505
|
"admin.app.createEntity": [
|
|
6409
|
-
{ title: "Table lifecycle", file: "
|
|
6506
|
+
{ title: "Table lifecycle", file: "docs/runtime-reference/table-lifecycle.md" },
|
|
6507
|
+
examplesIndexDocHint
|
|
6508
|
+
],
|
|
6509
|
+
"admin.table.adminGetEntityInfo": [
|
|
6510
|
+
{ title: "Table lifecycle", file: "docs/runtime-reference/table-lifecycle.md" },
|
|
6511
|
+
examplesIndexDocHint
|
|
6512
|
+
],
|
|
6513
|
+
"admin.table.adminSaveEntity": [
|
|
6514
|
+
{ title: "Table schema cheatsheet", file: "docs/runtime-reference/entity-schema.md" },
|
|
6515
|
+
{ title: "Field type index", file: "docs/runtime-reference/entity-schema/README.md" },
|
|
6516
|
+
{ title: "Table lifecycle", file: "docs/runtime-reference/table-lifecycle.md" },
|
|
6517
|
+
{ title: "Row CRUD", file: "docs/runtime-reference/row-crud.md" },
|
|
6410
6518
|
examplesIndexDocHint
|
|
6411
6519
|
],
|
|
6412
|
-
"admin.
|
|
6413
|
-
{ title: "
|
|
6520
|
+
"admin.access-rule.createEntityIngress": [
|
|
6521
|
+
{ title: "Access rule", file: "docs/runtime-reference/access-rule.md" },
|
|
6414
6522
|
examplesIndexDocHint
|
|
6415
6523
|
],
|
|
6416
|
-
"admin.
|
|
6417
|
-
{ title: "
|
|
6418
|
-
{ title: "Table lifecycle", file: "/opt/arcubase-sdk/docs/runtime-reference/table-lifecycle.md" },
|
|
6419
|
-
{ title: "Row CRUD", file: "/opt/arcubase-sdk/docs/runtime-reference/row-crud.md" },
|
|
6524
|
+
"admin.access-rule.updateEntityIngress": [
|
|
6525
|
+
{ title: "Access rule", file: "docs/runtime-reference/access-rule.md" },
|
|
6420
6526
|
examplesIndexDocHint
|
|
6421
6527
|
],
|
|
6422
|
-
"user.
|
|
6423
|
-
{ title: "Row CRUD", file: "
|
|
6424
|
-
{ title: "Uploads", file: "
|
|
6528
|
+
"user.row.insertEntity": [
|
|
6529
|
+
{ title: "Row CRUD", file: "docs/runtime-reference/row-crud.md" },
|
|
6530
|
+
{ title: "Uploads", file: "docs/runtime-reference/uploads.md" },
|
|
6425
6531
|
examplesIndexDocHint
|
|
6426
6532
|
],
|
|
6427
|
-
"user.
|
|
6428
|
-
{ title: "Search and bulk actions", file: "
|
|
6429
|
-
|
|
6533
|
+
"user.row.queryEntity": [
|
|
6534
|
+
{ title: "Search and bulk actions", file: "docs/runtime-reference/search-and-bulk-actions.md" },
|
|
6535
|
+
conditionDocHint,
|
|
6536
|
+
{ title: "Row CRUD", file: "docs/runtime-reference/row-crud.md" },
|
|
6430
6537
|
examplesIndexDocHint
|
|
6431
6538
|
],
|
|
6432
|
-
"user.
|
|
6433
|
-
{ title: "Row CRUD", file: "
|
|
6539
|
+
"user.row.getEntityRow": [
|
|
6540
|
+
{ title: "Row CRUD", file: "docs/runtime-reference/row-crud.md" },
|
|
6434
6541
|
examplesIndexDocHint
|
|
6435
6542
|
],
|
|
6436
|
-
"user.
|
|
6437
|
-
{ title: "Row CRUD", file: "
|
|
6438
|
-
{ title: "Uploads", file: "
|
|
6543
|
+
"user.row.updateEntityRow": [
|
|
6544
|
+
{ title: "Row CRUD", file: "docs/runtime-reference/row-crud.md" },
|
|
6545
|
+
{ title: "Uploads", file: "docs/runtime-reference/uploads.md" },
|
|
6439
6546
|
examplesIndexDocHint
|
|
6440
6547
|
],
|
|
6441
|
-
"user.
|
|
6442
|
-
|
|
6548
|
+
"user.row.queryEntitySelection": [
|
|
6549
|
+
selectionDocHint,
|
|
6550
|
+
conditionDocHint,
|
|
6551
|
+
{ title: "Search and bulk actions", file: "docs/runtime-reference/search-and-bulk-actions.md" },
|
|
6443
6552
|
examplesIndexDocHint
|
|
6444
6553
|
],
|
|
6445
|
-
"user.
|
|
6446
|
-
{ title: "Row CRUD", file: "
|
|
6554
|
+
"user.row.deleteEntityRow": [
|
|
6555
|
+
{ title: "Row CRUD", file: "docs/runtime-reference/row-crud.md" },
|
|
6447
6556
|
examplesIndexDocHint
|
|
6448
6557
|
],
|
|
6449
|
-
"user.
|
|
6450
|
-
{ title: "Row CRUD", file: "
|
|
6558
|
+
"user.row.restoreEntityRow": [
|
|
6559
|
+
{ title: "Row CRUD", file: "docs/runtime-reference/row-crud.md" },
|
|
6451
6560
|
examplesIndexDocHint
|
|
6452
6561
|
],
|
|
6453
|
-
"user.
|
|
6454
|
-
|
|
6562
|
+
"user.row.updateEntityBulk": [
|
|
6563
|
+
selectionDocHint,
|
|
6564
|
+
conditionDocHint,
|
|
6565
|
+
{ title: "Search and bulk actions", file: "docs/runtime-reference/search-and-bulk-actions.md" },
|
|
6455
6566
|
examplesIndexDocHint
|
|
6456
6567
|
]
|
|
6457
6568
|
};
|
|
6458
|
-
function getCommandDocHints(operation) {
|
|
6569
|
+
function getCommandDocHints(operation, env = process.env) {
|
|
6459
6570
|
const key = String(operation || "").trim();
|
|
6460
6571
|
if (!key) return [];
|
|
6461
|
-
return commandDocHintIndex[key] ?? [];
|
|
6462
|
-
}
|
|
6463
|
-
|
|
6464
|
-
// src/runtime/upload.ts
|
|
6465
|
-
import fs2 from "fs";
|
|
6466
|
-
import path from "path";
|
|
6467
|
-
function readUploadSource(sourcePath) {
|
|
6468
|
-
const absolutePath = path.resolve(sourcePath);
|
|
6469
|
-
if (!fs2.existsSync(absolutePath)) {
|
|
6470
|
-
throw new CLIError("UPLOAD_SOURCE_NOT_FOUND", `upload source file does not exist: ${sourcePath}`, 2);
|
|
6471
|
-
}
|
|
6472
|
-
const stat = fs2.statSync(absolutePath);
|
|
6473
|
-
if (!stat.isFile()) {
|
|
6474
|
-
throw new CLIError("UPLOAD_SOURCE_INVALID", `upload source path must be a file: ${sourcePath}`, 2);
|
|
6475
|
-
}
|
|
6476
|
-
return {
|
|
6477
|
-
absolutePath,
|
|
6478
|
-
bytes: fs2.readFileSync(absolutePath)
|
|
6479
|
-
};
|
|
6480
|
-
}
|
|
6481
|
-
function parseJSONResponse(raw) {
|
|
6482
|
-
try {
|
|
6483
|
-
return raw ? JSON.parse(raw) : null;
|
|
6484
|
-
} catch {
|
|
6485
|
-
return raw;
|
|
6486
|
-
}
|
|
6487
|
-
}
|
|
6488
|
-
function requireTokenPayload(payload) {
|
|
6489
|
-
if (payload && typeof payload === "object" && payload.error) {
|
|
6490
|
-
const upstreamError = payload.error;
|
|
6491
|
-
const message = typeof upstreamError === "object" && upstreamError && "message" in upstreamError && typeof upstreamError.message === "string" ? upstreamError.message : typeof upstreamError === "string" ? upstreamError : JSON.stringify(upstreamError);
|
|
6492
|
-
throw new CLIError("UPSTREAM_BODY_ERROR", message, 1, {
|
|
6493
|
-
endpoint: "/api/upload/token",
|
|
6494
|
-
method: "POST",
|
|
6495
|
-
traceId: typeof payload.trace_id === "string" ? payload.trace_id : void 0,
|
|
6496
|
-
upstreamError
|
|
6497
|
-
});
|
|
6498
|
-
}
|
|
6499
|
-
if (!payload?.data || typeof payload.data !== "object") {
|
|
6500
|
-
throw new CLIError("UPLOAD_TOKEN_INVALID", "upload token response did not include data", 1);
|
|
6501
|
-
}
|
|
6502
|
-
return payload.data;
|
|
6503
|
-
}
|
|
6504
|
-
function renderUploadHelp() {
|
|
6505
|
-
return [
|
|
6506
|
-
"arcubase upload <local-file> [flags]",
|
|
6507
|
-
"",
|
|
6508
|
-
"purpose:",
|
|
6509
|
-
" - upload one local file through Arcubase",
|
|
6510
|
-
" - return a field value that can be used directly in file or image row payloads",
|
|
6511
|
-
"",
|
|
6512
|
-
"flags:",
|
|
6513
|
-
" --filename <name> override the uploaded filename stored in Arcubase",
|
|
6514
|
-
" --global request a global upload token instead of a tenant-scoped token",
|
|
6515
|
-
"",
|
|
6516
|
-
"result shape:",
|
|
6517
|
-
" - data is a JSON array",
|
|
6518
|
-
" - use that array directly as the value of a file or image field in insert/update payloads",
|
|
6519
|
-
"",
|
|
6520
|
-
"example:",
|
|
6521
|
-
" arcubase upload ./contract.pdf",
|
|
6522
|
-
" arcubase upload ./photo.jpg --filename lead-photo.jpg",
|
|
6523
|
-
"",
|
|
6524
|
-
"docs:",
|
|
6525
|
-
" - Uploads: /opt/arcubase-sdk/docs/runtime-reference/uploads.md",
|
|
6526
|
-
" - Row CRUD: /opt/arcubase-sdk/docs/runtime-reference/row-crud.md",
|
|
6527
|
-
" - File field: /opt/arcubase-sdk/docs/runtime-reference/entity-schema/file.md",
|
|
6528
|
-
" - Image field: /opt/arcubase-sdk/docs/runtime-reference/entity-schema/image.md"
|
|
6529
|
-
].join("\n");
|
|
6530
|
-
}
|
|
6531
|
-
async function uploadLocalFile(env, sourcePath, options, fetchImpl = fetch) {
|
|
6532
|
-
const { absolutePath, bytes } = readUploadSource(sourcePath);
|
|
6533
|
-
const filename = options.filename && options.filename.trim() || path.basename(absolutePath);
|
|
6534
|
-
const tokenResponse = await fetchImpl(buildURL(env.ARCUBASE_BASE_URL, "/api/upload/token"), {
|
|
6535
|
-
method: "POST",
|
|
6536
|
-
headers: {
|
|
6537
|
-
...buildRequestHeaders(env),
|
|
6538
|
-
"Content-Type": "application/json"
|
|
6539
|
-
},
|
|
6540
|
-
body: JSON.stringify({
|
|
6541
|
-
global: Boolean(options.global)
|
|
6542
|
-
})
|
|
6543
|
-
});
|
|
6544
|
-
const tokenRaw = await tokenResponse.text();
|
|
6545
|
-
const tokenParsed = parseJSONResponse(tokenRaw);
|
|
6546
|
-
if (!tokenResponse.ok) {
|
|
6547
|
-
throw new CLIError("UPLOAD_TOKEN_REQUEST_FAILED", typeof tokenParsed === "string" ? tokenParsed : JSON.stringify(tokenParsed), 1, {
|
|
6548
|
-
endpoint: "/api/upload/token",
|
|
6549
|
-
method: "POST"
|
|
6550
|
-
});
|
|
6551
|
-
}
|
|
6552
|
-
const tokenData = requireTokenPayload(tokenParsed);
|
|
6553
|
-
if (tokenData.mode !== "aliyun-oss" && tokenData.mode !== "s3-post-policy") {
|
|
6554
|
-
throw new CLIError("UPLOAD_MODE_UNSUPPORTED", `unsupported upload mode: ${String(tokenData.mode || "")}`, 1);
|
|
6555
|
-
}
|
|
6556
|
-
if (!tokenData.token_data?.dir || !tokenData.token_data.policy || !tokenData.token_data.host) {
|
|
6557
|
-
throw new CLIError("UPLOAD_TOKEN_INVALID", "upload token response is missing required token_data fields", 1);
|
|
6558
|
-
}
|
|
6559
|
-
if (tokenData.id === void 0 || tokenData.id === null || tokenData.id === "") {
|
|
6560
|
-
throw new CLIError("UPLOAD_TOKEN_INVALID", "upload token response is missing id", 1);
|
|
6561
|
-
}
|
|
6562
|
-
const form = new FormData();
|
|
6563
|
-
form.append("key", `${tokenData.token_data.dir}${filename}`);
|
|
6564
|
-
form.append("policy", tokenData.token_data.policy);
|
|
6565
|
-
if (tokenData.mode === "aliyun-oss") {
|
|
6566
|
-
if (!tokenData.token_data.accessid || !tokenData.token_data.signature) {
|
|
6567
|
-
throw new CLIError("UPLOAD_TOKEN_INVALID", "upload token response is missing required token_data fields", 1);
|
|
6568
|
-
}
|
|
6569
|
-
form.append("OSSAccessKeyId", tokenData.token_data.accessid);
|
|
6570
|
-
form.append("success_action_status", "200");
|
|
6571
|
-
form.append("signature", tokenData.token_data.signature);
|
|
6572
|
-
} else {
|
|
6573
|
-
if (!tokenData.token_data.x_amz_algorithm || !tokenData.token_data.x_amz_credential || !tokenData.token_data.x_amz_date || !tokenData.token_data.x_amz_signature) {
|
|
6574
|
-
throw new CLIError("UPLOAD_TOKEN_INVALID", "upload token response is missing required s3 token_data fields", 1);
|
|
6575
|
-
}
|
|
6576
|
-
form.append("x-amz-algorithm", tokenData.token_data.x_amz_algorithm);
|
|
6577
|
-
form.append("x-amz-credential", tokenData.token_data.x_amz_credential);
|
|
6578
|
-
form.append("x-amz-date", tokenData.token_data.x_amz_date);
|
|
6579
|
-
form.append("x-amz-signature", tokenData.token_data.x_amz_signature);
|
|
6580
|
-
}
|
|
6581
|
-
form.append("file", new Blob([new Uint8Array(bytes)]), filename);
|
|
6582
|
-
const uploadResponse = await fetchImpl(tokenData.token_data.host, {
|
|
6583
|
-
method: "POST",
|
|
6584
|
-
body: form
|
|
6585
|
-
});
|
|
6586
|
-
const uploadRaw = await uploadResponse.text();
|
|
6587
|
-
if (!uploadResponse.ok) {
|
|
6588
|
-
throw new CLIError("UPLOAD_TRANSFER_FAILED", uploadRaw || `upload failed with status ${uploadResponse.status}`, 1, {
|
|
6589
|
-
endpoint: tokenData.token_data.host,
|
|
6590
|
-
method: "POST"
|
|
6591
|
-
});
|
|
6592
|
-
}
|
|
6593
|
-
return [
|
|
6594
|
-
{
|
|
6595
|
-
upload_id: tokenData.id,
|
|
6596
|
-
file: filename,
|
|
6597
|
-
file_name: filename,
|
|
6598
|
-
meta: {}
|
|
6599
|
-
}
|
|
6600
|
-
];
|
|
6572
|
+
return resolveDocHintFiles(commandDocHintIndex[key] ?? [], env);
|
|
6601
6573
|
}
|
|
6602
6574
|
|
|
6603
6575
|
// src/runtime/execute.ts
|
|
@@ -6608,24 +6580,27 @@ function renderRootHelp(scope) {
|
|
|
6608
6580
|
`${binary} <command> [subcommand] [flags]`,
|
|
6609
6581
|
"",
|
|
6610
6582
|
...scope === "admin" ? ["use arcubase-admin for app, table, access-rule, and workflow management", ""] : ["use arcubase for entry, table, row, upload, profile, and workflow actions", ""],
|
|
6583
|
+
"prefer --body-json <json-string> for normal payloads, including table schema; use --body-file only when JSON is too large for one tool call",
|
|
6584
|
+
"",
|
|
6611
6585
|
"modules:",
|
|
6612
|
-
...items
|
|
6613
|
-
...scope === "user" ? ["", "special commands:", " - upload <local-file>"] : []
|
|
6586
|
+
...items
|
|
6614
6587
|
].join("\n");
|
|
6615
6588
|
}
|
|
6616
|
-
function renderModuleHelp(scope, moduleName) {
|
|
6589
|
+
function renderModuleHelp(scope, moduleName, env = process.env) {
|
|
6617
6590
|
const items = listModuleCommands(scope, moduleName);
|
|
6618
6591
|
if (items.length === 0) {
|
|
6619
6592
|
const suggestions = findCommandSuggestions(moduleName, "").map((item) => `${item.binary} ${item.moduleName}${item.commandName ? ` ${item.commandName}` : ""}`);
|
|
6620
6593
|
throw new CLIError("UNKNOWN_MODULE", `unknown module: ${moduleName}`, 2, suggestions.length > 0 ? { suggestions } : void 0);
|
|
6621
6594
|
}
|
|
6622
6595
|
if (items.length === 1 && items[0].commandPath.length === 1) {
|
|
6623
|
-
return renderCommandHelp(scope, moduleName);
|
|
6596
|
+
return renderCommandHelp(scope, moduleName, void 0, env);
|
|
6624
6597
|
}
|
|
6625
6598
|
return [
|
|
6626
6599
|
`${scope === "admin" ? "arcubase-admin" : "arcubase"} ${moduleName} <command> [flags]`,
|
|
6627
6600
|
"",
|
|
6628
6601
|
...scope === "admin" ? ["use arcubase-admin for app, table, access-rule, and workflow management", ""] : ["use arcubase for entry, table, row, upload, profile, and workflow actions", ""],
|
|
6602
|
+
"prefer --body-json <json-string> for normal payloads, including table schema; use --body-file only when JSON is too large for one tool call",
|
|
6603
|
+
"",
|
|
6629
6604
|
"commands:",
|
|
6630
6605
|
...items.filter((item) => item.commandPath.length > 1).map((item) => ` - ${item.commandPath[1]}`)
|
|
6631
6606
|
].join("\n");
|
|
@@ -6634,39 +6609,68 @@ function buildUnknownCommandDetails(scope, moduleName, commandName) {
|
|
|
6634
6609
|
const suggestions = findCommandSuggestions(moduleName, commandName).map((item) => `${item.binary} ${item.moduleName}${item.commandName ? ` ${item.commandName}` : ""}`);
|
|
6635
6610
|
return suggestions.length > 0 ? { suggestions } : void 0;
|
|
6636
6611
|
}
|
|
6637
|
-
function
|
|
6612
|
+
function sdkPath2(file, env = process.env) {
|
|
6613
|
+
return resolveArcubaseSDKPath(file, env);
|
|
6614
|
+
}
|
|
6615
|
+
function renderCommandHelp(scope, moduleName, commandName, env = process.env) {
|
|
6638
6616
|
const command = findCommand(scope, moduleName, commandName);
|
|
6639
6617
|
if (!command) {
|
|
6640
6618
|
throw new CLIError("UNKNOWN_COMMAND", `unknown command: ${moduleName}${commandName ? ` ${commandName}` : ""}`, 2, buildUnknownCommandDetails(scope, moduleName, commandName ?? ""));
|
|
6641
6619
|
}
|
|
6642
6620
|
const docHints = [
|
|
6643
|
-
...getCommandDocHints(`${scope}.${command.module}.${command.functionName}
|
|
6644
|
-
...command.requestType ? getDocHints(command.requestType) : []
|
|
6621
|
+
...getCommandDocHints(`${scope}.${command.module}.${command.functionName}`, env),
|
|
6622
|
+
...command.requestType ? getDocHints(command.requestType, env) : []
|
|
6645
6623
|
].filter((item, index, list) => list.findIndex((candidate) => candidate.file === item.file) === index);
|
|
6624
|
+
const typeHints = command.requestType ? getTypeHints(command.requestType, env) : [];
|
|
6646
6625
|
const pathFlags = command.pathParams.filter((item) => !getFixedValue(item)).map((item) => `--${item.flag}`);
|
|
6647
|
-
const queryFlags = command
|
|
6626
|
+
const queryFlags = visibleQueryParams(command).map((item) => `--${item.flag}`);
|
|
6627
|
+
const isTableCreate = scope === "admin" && command.commandPath[0] === "table" && command.commandPath[1] === "create";
|
|
6628
|
+
const bodyTypeText = isTableCreate ? "TableCreateWithSchema" : command.requestType;
|
|
6629
|
+
const tableCreateExampleBody = JSON.stringify(buildTableCreateExampleBody());
|
|
6648
6630
|
return [
|
|
6649
6631
|
`${scope === "admin" ? "arcubase-admin" : "arcubase"} ${command.commandPath.join(" ")}`,
|
|
6650
6632
|
`method: ${command.method}`,
|
|
6651
6633
|
`endpoint: ${normalizeExternalEndpoint(command.endpoint)}`,
|
|
6652
|
-
command.requestType ? `body: ${
|
|
6634
|
+
command.requestType ? `body: ${bodyTypeText} via --body-json <json-string> | --body-file <file>.json` : "body: none",
|
|
6653
6635
|
queryFlags.length ? `query flags: ${queryFlags.join(", ")}, --query-file` : "query flags: --query-file",
|
|
6654
6636
|
pathFlags.length ? `path flags: ${pathFlags.join(", ")}` : "path flags: none",
|
|
6637
|
+
...isTableCreate ? [
|
|
6638
|
+
"body-json example:",
|
|
6639
|
+
` - ${tableCreateExampleBody}`,
|
|
6640
|
+
"body rules:",
|
|
6641
|
+
" - fields must be non-empty; empty table shell creation is not allowed",
|
|
6642
|
+
" - field_id_seq must be greater than every field.id",
|
|
6643
|
+
" - use text, not string; use member, not user",
|
|
6644
|
+
" - for select/radio/checkbox/status, use options.options.items",
|
|
6645
|
+
"schema refs:",
|
|
6646
|
+
` - Table schema cheatsheet: ${sdkPath2("docs/runtime-reference/entity-schema.md", env)}`,
|
|
6647
|
+
` - Field type index: ${sdkPath2("docs/runtime-reference/entity-schema/README.md", env)}`
|
|
6648
|
+
] : [],
|
|
6655
6649
|
...scope === "admin" && command.commandPath[0] === "table" && command.commandPath[1] === "update-schema" ? [
|
|
6656
6650
|
"next step:",
|
|
6651
|
+
" - prefer --body-json for schema save to avoid file creation and JSON file corruption",
|
|
6657
6652
|
" - switch to arcubase for row operations",
|
|
6658
|
-
" - row create: arcubase row create --app-id <app_id> --table-id <table_id> --body-file insert.json",
|
|
6659
|
-
" - row query: arcubase row query --app-id <app_id> --table-id <table_id> --body-file query.json"
|
|
6653
|
+
" - row create: arcubase row create --app-id <app_id> --table-id <table_id> --body-json <json-string> | --body-file insert.json",
|
|
6654
|
+
" - row query: arcubase row query --app-id <app_id> --table-id <table_id> --body-json <json-string> | --body-file query.json"
|
|
6660
6655
|
] : [],
|
|
6661
6656
|
...scope === "admin" && command.commandPath[0] === "access-rule" && command.commandPath[1] === "update" ? [
|
|
6662
6657
|
"body-json examples:",
|
|
6663
6658
|
' - enable: {"update":["enabled"],"enabled":true}',
|
|
6664
6659
|
' - rename: {"update":["name"],"name":"Sales read only"}',
|
|
6665
|
-
' - update
|
|
6660
|
+
' - update policy: {"update":["options"],"options":{"policy":{"key":"custom","actions":["view","add","edit"],"all_fields_read":true,"all_fields_write":true,"fields":[{"key":":1002","read":false,"write":false,"report":false}]},"list_options":{}}}'
|
|
6661
|
+
] : [],
|
|
6662
|
+
...scope === "admin" && command.commandPath[0] === "access-rule" && command.commandPath[1] === "create" ? [
|
|
6663
|
+
"body-json examples:",
|
|
6664
|
+
` - full access: ${JSON.stringify(buildFullAccessRuleBody())}`,
|
|
6665
|
+
` - hide field: ${JSON.stringify(buildHiddenFieldAccessRuleBody())}`,
|
|
6666
|
+
"success requires:",
|
|
6667
|
+
" - result.enabled must be true",
|
|
6668
|
+
' - options.user_scope[].type is "user" for tenant users',
|
|
6669
|
+
' - hidden fields use colon field keys such as ":1002"'
|
|
6666
6670
|
] : [],
|
|
6667
6671
|
...scope === "admin" && command.commandPath[0] === "access-rule" && command.commandPath[1] === "assign-users" ? [
|
|
6668
6672
|
"body-json example:",
|
|
6669
|
-
' - {"update":["user_scope"],"options":{"user_scope":[{"type":"
|
|
6673
|
+
' - {"update":["user_scope"],"options":{"user_scope":[{"type":"user","id":2188889901}]}}',
|
|
6670
6674
|
"success requires:",
|
|
6671
6675
|
" - result.enabled must be true",
|
|
6672
6676
|
" - result.options.user_scope must contain the assigned numeric TenantUser.ID values",
|
|
@@ -6674,7 +6678,8 @@ function renderCommandHelp(scope, moduleName, commandName) {
|
|
|
6674
6678
|
" - Do not copy hash arcubaseTenantUserId into PermitUserScope.id",
|
|
6675
6679
|
" - If result.enabled is false, enable the rule first and retry assign-users"
|
|
6676
6680
|
] : [],
|
|
6677
|
-
...docHints.length > 0 ? ["docs:", ...docHints.map((item) => ` - ${item.title}: ${item.file}`)] : []
|
|
6681
|
+
...docHints.length > 0 ? ["docs:", ...docHints.map((item) => ` - ${item.title}: ${item.file}`)] : [],
|
|
6682
|
+
...typeHints.length > 0 ? ["types:", ...typeHints.map((item) => ` - ${item.symbol}: ${item.file}`)] : []
|
|
6678
6683
|
].join("\n");
|
|
6679
6684
|
}
|
|
6680
6685
|
function coerceScalar(value, typeText) {
|
|
@@ -6716,16 +6721,126 @@ function buildScalarQuery(command, flags) {
|
|
|
6716
6721
|
return void 0;
|
|
6717
6722
|
}
|
|
6718
6723
|
const out = {};
|
|
6719
|
-
for (const scalar of command
|
|
6724
|
+
for (const scalar of effectiveQueryParams(command)) {
|
|
6720
6725
|
const value = getFixedValue(scalar) ?? flagValue(flags, scalar.flag);
|
|
6721
6726
|
if (value === void 0) continue;
|
|
6722
6727
|
out[scalar.key] = coerceScalar(value, scalar.type);
|
|
6723
6728
|
}
|
|
6724
6729
|
return Object.keys(out).length > 0 ? out : void 0;
|
|
6725
6730
|
}
|
|
6731
|
+
function validateKnownFlags(command, flags, env = process.env) {
|
|
6732
|
+
const allowed = /* @__PURE__ */ new Set(["help", "body-file", "body-json", "query-file"]);
|
|
6733
|
+
for (const mapping of command.pathParams) {
|
|
6734
|
+
if (!getFixedValue(mapping)) {
|
|
6735
|
+
allowed.add(mapping.flag);
|
|
6736
|
+
}
|
|
6737
|
+
}
|
|
6738
|
+
for (const query of visibleQueryParams(command)) {
|
|
6739
|
+
if (!getFixedValue(query)) {
|
|
6740
|
+
allowed.add(query.flag);
|
|
6741
|
+
}
|
|
6742
|
+
}
|
|
6743
|
+
for (const flag of Object.keys(flags)) {
|
|
6744
|
+
if (!allowed.has(flag)) {
|
|
6745
|
+
throw new CLIError("UNKNOWN_FLAG", `unknown flag --${flag} for ${command.commandPath.join(" ")}`, 2, {
|
|
6746
|
+
...buildUnknownFlagDetails(command, flag, env)
|
|
6747
|
+
});
|
|
6748
|
+
}
|
|
6749
|
+
}
|
|
6750
|
+
}
|
|
6751
|
+
function buildUnknownFlagDetails(command, flag, env = process.env) {
|
|
6752
|
+
const operation = command.commandPath.join(" ");
|
|
6753
|
+
const details = {
|
|
6754
|
+
operation,
|
|
6755
|
+
hint: `run ${operation} --help for the supported flags`
|
|
6756
|
+
};
|
|
6757
|
+
if (command.requestType) {
|
|
6758
|
+
details.requestType = command.requestType;
|
|
6759
|
+
details.tsHints = getTypeHints(command.requestType, env);
|
|
6760
|
+
details.docHints = getDocHints(command.requestType, env);
|
|
6761
|
+
details.commonMistakes = [
|
|
6762
|
+
`do not pass request body fields as --${flag}`,
|
|
6763
|
+
"put request body fields inside --body-json <json-string>"
|
|
6764
|
+
];
|
|
6765
|
+
details.suggestions = [`retry with: ${command.commandPath.join(" ")} ${command.pathParams.filter((item) => !getFixedValue(item)).map((item) => `--${item.flag} <${item.flag.replace(/-/g, "_")}>`).join(" ")} --body-json '<json>'`.replace(/\s+/g, " ").trim()];
|
|
6766
|
+
}
|
|
6767
|
+
if (command.commandPath[0] === "row" && command.commandPath[1] === "query" && ["limit", "offset", "search", "sorts", "view-mode"].includes(flag)) {
|
|
6768
|
+
details.shapeHint = { limit: 20, offset: 0, search: { text_search: "SO-1001" } };
|
|
6769
|
+
details.suggestions = [`retry with: row query --app-id <app_id> --table-id <table_id> --body-json '{"limit":20,"offset":0}'`];
|
|
6770
|
+
}
|
|
6771
|
+
if (command.commandPath[0] === "table" && command.commandPath[1] === "dataset" && ["app-id", "table-id"].includes(flag)) {
|
|
6772
|
+
details.hint = "table dataset uses --dataset-id and --node-id; use table get for app/table metadata";
|
|
6773
|
+
details.suggestions = [
|
|
6774
|
+
"retry metadata read with: table get --app-id <app_id> --table-id <table_id>",
|
|
6775
|
+
"retry dataset read with: table dataset --dataset-id <dataset_id> --node-id <node_id>"
|
|
6776
|
+
];
|
|
6777
|
+
}
|
|
6778
|
+
return details;
|
|
6779
|
+
}
|
|
6780
|
+
function visibleQueryParams(command) {
|
|
6781
|
+
if (!command) return [];
|
|
6782
|
+
return effectiveQueryParams(command).filter((item) => !getFixedValue(item));
|
|
6783
|
+
}
|
|
6784
|
+
function effectiveQueryParams(command) {
|
|
6785
|
+
if (!command) return [];
|
|
6786
|
+
return command.queryParams.filter((item) => {
|
|
6787
|
+
if (rowCommandNeedsPolicy(command) && item.key === "policy_id") {
|
|
6788
|
+
return false;
|
|
6789
|
+
}
|
|
6790
|
+
return true;
|
|
6791
|
+
});
|
|
6792
|
+
}
|
|
6726
6793
|
function isRecord2(value) {
|
|
6727
6794
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
6728
6795
|
}
|
|
6796
|
+
function stringifyUpstreamBody(value) {
|
|
6797
|
+
if (typeof value === "string") return value;
|
|
6798
|
+
if (value == null) return "";
|
|
6799
|
+
try {
|
|
6800
|
+
return JSON.stringify(value);
|
|
6801
|
+
} catch {
|
|
6802
|
+
return String(value);
|
|
6803
|
+
}
|
|
6804
|
+
}
|
|
6805
|
+
function extractTraceID(value) {
|
|
6806
|
+
if (!isRecord2(value)) return void 0;
|
|
6807
|
+
if (typeof value.trace_id === "string") return value.trace_id;
|
|
6808
|
+
if (typeof value.request_id === "string") return value.request_id;
|
|
6809
|
+
return void 0;
|
|
6810
|
+
}
|
|
6811
|
+
function upstreamErrorMessage(value) {
|
|
6812
|
+
if (isRecord2(value) && typeof value.message === "string") return value.message;
|
|
6813
|
+
if (typeof value === "string") return value;
|
|
6814
|
+
return stringifyUpstreamBody(value);
|
|
6815
|
+
}
|
|
6816
|
+
function throwUpstreamHTTPError(endpoint, method, response, parsedResponse) {
|
|
6817
|
+
const upstreamError = isRecord2(parsedResponse) && parsedResponse.error ? parsedResponse.error : void 0;
|
|
6818
|
+
const body = stringifyUpstreamBody(parsedResponse);
|
|
6819
|
+
throw new CLIError(
|
|
6820
|
+
"UPSTREAM_REQUEST_FAILED",
|
|
6821
|
+
upstreamError ? upstreamErrorMessage(upstreamError) : body || `HTTP ${response.status}`,
|
|
6822
|
+
1,
|
|
6823
|
+
{
|
|
6824
|
+
endpoint,
|
|
6825
|
+
method,
|
|
6826
|
+
status: response.status,
|
|
6827
|
+
traceId: extractTraceID(parsedResponse),
|
|
6828
|
+
responseBody: body,
|
|
6829
|
+
...upstreamError ? { upstreamError } : {}
|
|
6830
|
+
}
|
|
6831
|
+
);
|
|
6832
|
+
}
|
|
6833
|
+
async function fetchUpstream(url, init, endpoint, method, fetchImpl) {
|
|
6834
|
+
try {
|
|
6835
|
+
return await fetchImpl(url, init);
|
|
6836
|
+
} catch (error) {
|
|
6837
|
+
throw new CLIError("UPSTREAM_NETWORK_ERROR", error instanceof Error ? error.message : String(error), 1, {
|
|
6838
|
+
endpoint,
|
|
6839
|
+
method,
|
|
6840
|
+
reason: "network or DNS failure before Arcubase returned an HTTP response"
|
|
6841
|
+
});
|
|
6842
|
+
}
|
|
6843
|
+
}
|
|
6729
6844
|
function extractEntityFields(payload) {
|
|
6730
6845
|
const candidate = isRecord2(payload) && isRecord2(payload.data) ? payload.data : payload;
|
|
6731
6846
|
if (!isRecord2(candidate) || !Array.isArray(candidate.fields)) {
|
|
@@ -6738,10 +6853,12 @@ function extractEntityFields(payload) {
|
|
|
6738
6853
|
}));
|
|
6739
6854
|
}
|
|
6740
6855
|
async function fetchEntityFields(runtimeEnv, appId, entityId, fetchImpl) {
|
|
6741
|
-
const
|
|
6856
|
+
const endpoint = `/api/entity/${appId}/${entityId}`;
|
|
6857
|
+
const encodedEndpoint = `/api/entity/${encodeURIComponent(appId)}/${encodeURIComponent(entityId)}`;
|
|
6858
|
+
const response = await fetchUpstream(buildURL(runtimeEnv.ARCUBASE_BASE_URL, encodedEndpoint), {
|
|
6742
6859
|
method: "GET",
|
|
6743
6860
|
headers: buildRequestHeaders(runtimeEnv)
|
|
6744
|
-
});
|
|
6861
|
+
}, endpoint, "GET", fetchImpl);
|
|
6745
6862
|
const raw = await response.text();
|
|
6746
6863
|
let parsedResponse = raw;
|
|
6747
6864
|
try {
|
|
@@ -6750,14 +6867,15 @@ async function fetchEntityFields(runtimeEnv, appId, entityId, fetchImpl) {
|
|
|
6750
6867
|
parsedResponse = raw;
|
|
6751
6868
|
}
|
|
6752
6869
|
if (!response.ok) {
|
|
6753
|
-
|
|
6870
|
+
throwUpstreamHTTPError(endpoint, "GET", response, parsedResponse);
|
|
6754
6871
|
}
|
|
6755
6872
|
if (isRecord2(parsedResponse) && parsedResponse.error) {
|
|
6756
6873
|
const upstreamError = parsedResponse.error;
|
|
6757
|
-
const upstreamMessage =
|
|
6874
|
+
const upstreamMessage = upstreamErrorMessage(upstreamError);
|
|
6758
6875
|
throw new CLIError("UPSTREAM_BODY_ERROR", upstreamMessage, 1, {
|
|
6759
|
-
endpoint
|
|
6876
|
+
endpoint,
|
|
6760
6877
|
method: "GET",
|
|
6878
|
+
traceId: extractTraceID(parsedResponse),
|
|
6761
6879
|
upstreamError
|
|
6762
6880
|
});
|
|
6763
6881
|
}
|
|
@@ -6801,75 +6919,186 @@ async function validateFileFieldPayloads(scope, command, runtimeEnv, flags, body
|
|
|
6801
6919
|
const fieldPath = command.functionName === "updateEntityRow" ? `body.data.${fieldId}` : `body.fields.${fieldId}`;
|
|
6802
6920
|
const fieldName = field.label ? `${field.label} (${field.type})` : `${field.type} field ${fieldId}`;
|
|
6803
6921
|
if (typeof value === "string") {
|
|
6804
|
-
const guidance = looksLikeLocalFilePath(value) ? `do not put a local file path directly into ${fieldName};
|
|
6922
|
+
const guidance = looksLikeLocalFilePath(value) ? `do not put a local file path directly into ${fieldName}; use arcubase upload token flow and pass the returned upload value array` : `${fieldName} must be an upload value array, not a string`;
|
|
6805
6923
|
throw new CLIError("BODY_VALIDATION_FAILED", guidance, 2, {
|
|
6806
6924
|
operation: `${scope}.${command.module}.${command.functionName}`,
|
|
6807
6925
|
requestType: command.requestType ?? void 0,
|
|
6808
6926
|
issues: [{ path: fieldPath, message: guidance }],
|
|
6809
6927
|
docHints: [
|
|
6810
|
-
{ title: "Uploads", file: "
|
|
6811
|
-
{ title: "Row CRUD", file: "
|
|
6928
|
+
{ title: "Uploads", file: sdkPath2("docs/runtime-reference/uploads.md", runtimeEnv) },
|
|
6929
|
+
{ title: "Row CRUD", file: sdkPath2("docs/runtime-reference/row-crud.md", runtimeEnv) }
|
|
6812
6930
|
]
|
|
6813
6931
|
});
|
|
6814
6932
|
}
|
|
6815
6933
|
if (isRecord2(value)) {
|
|
6816
|
-
const guidance = `${fieldName} must be an array.
|
|
6934
|
+
const guidance = `${fieldName} must be an upload value array. Use the upload token flow and pass the returned array directly`;
|
|
6817
6935
|
throw new CLIError("BODY_VALIDATION_FAILED", guidance, 2, {
|
|
6818
6936
|
operation: `${scope}.${command.module}.${command.functionName}`,
|
|
6819
6937
|
requestType: command.requestType ?? void 0,
|
|
6820
6938
|
issues: [{ path: fieldPath, message: guidance }],
|
|
6821
6939
|
docHints: [
|
|
6822
|
-
{ title: "Uploads", file: "
|
|
6823
|
-
{ title: "Row CRUD", file: "
|
|
6940
|
+
{ title: "Uploads", file: sdkPath2("docs/runtime-reference/uploads.md", runtimeEnv) },
|
|
6941
|
+
{ title: "Row CRUD", file: sdkPath2("docs/runtime-reference/row-crud.md", runtimeEnv) }
|
|
6824
6942
|
]
|
|
6825
6943
|
});
|
|
6826
6944
|
}
|
|
6827
6945
|
if (!Array.isArray(value)) {
|
|
6828
|
-
const guidance = `${fieldName} must be an
|
|
6946
|
+
const guidance = `${fieldName} must be an upload value array`;
|
|
6829
6947
|
throw new CLIError("BODY_VALIDATION_FAILED", guidance, 2, {
|
|
6830
6948
|
operation: `${scope}.${command.module}.${command.functionName}`,
|
|
6831
6949
|
requestType: command.requestType ?? void 0,
|
|
6832
6950
|
issues: [{ path: fieldPath, message: guidance }],
|
|
6833
6951
|
docHints: [
|
|
6834
|
-
{ title: "Uploads", file: "
|
|
6835
|
-
{ title: "Row CRUD", file: "
|
|
6952
|
+
{ title: "Uploads", file: sdkPath2("docs/runtime-reference/uploads.md", runtimeEnv) },
|
|
6953
|
+
{ title: "Row CRUD", file: sdkPath2("docs/runtime-reference/row-crud.md", runtimeEnv) }
|
|
6836
6954
|
]
|
|
6837
6955
|
});
|
|
6838
6956
|
}
|
|
6839
6957
|
for (const [index, item] of value.entries()) {
|
|
6840
6958
|
if (!isValidUploadEntry(item)) {
|
|
6841
|
-
const guidance = `${fieldName} entries must include upload_id or assets_id plus file and file_name. Use
|
|
6959
|
+
const guidance = `${fieldName} entries must include upload_id or assets_id plus file and file_name. Use the upload token flow and copy the returned array item as-is`;
|
|
6842
6960
|
throw new CLIError("BODY_VALIDATION_FAILED", guidance, 2, {
|
|
6843
6961
|
operation: `${scope}.${command.module}.${command.functionName}`,
|
|
6844
6962
|
requestType: command.requestType ?? void 0,
|
|
6845
6963
|
issues: [{ path: `${fieldPath}.${index}`, message: guidance }],
|
|
6846
6964
|
docHints: [
|
|
6847
|
-
{ title: "Uploads", file: "
|
|
6848
|
-
{ title: "Row CRUD", file: "
|
|
6965
|
+
{ title: "Uploads", file: sdkPath2("docs/runtime-reference/uploads.md", runtimeEnv) },
|
|
6966
|
+
{ title: "Row CRUD", file: sdkPath2("docs/runtime-reference/row-crud.md", runtimeEnv) }
|
|
6849
6967
|
]
|
|
6850
6968
|
});
|
|
6851
6969
|
}
|
|
6852
6970
|
}
|
|
6853
6971
|
}
|
|
6854
6972
|
}
|
|
6973
|
+
function buildTableCreateExampleBody() {
|
|
6974
|
+
return {
|
|
6975
|
+
name: "\u6295\u7968\u9879\u76EE",
|
|
6976
|
+
parent: 0,
|
|
6977
|
+
schema_version: 0,
|
|
6978
|
+
field_id_seq: 1003,
|
|
6979
|
+
layout: [[1001], [1002]],
|
|
6980
|
+
fields: [
|
|
6981
|
+
{
|
|
6982
|
+
id: 1001,
|
|
6983
|
+
label: "\u6295\u7968\u540D\u79F0",
|
|
6984
|
+
type: "text",
|
|
6985
|
+
required: true,
|
|
6986
|
+
unique: false,
|
|
6987
|
+
editable: true,
|
|
6988
|
+
visible: true,
|
|
6989
|
+
show_label: true,
|
|
6990
|
+
scannable: false,
|
|
6991
|
+
default_value_mode: 0,
|
|
6992
|
+
description: "",
|
|
6993
|
+
value: null,
|
|
6994
|
+
number_decimal: 0,
|
|
6995
|
+
depends: [],
|
|
6996
|
+
key: "vote_name",
|
|
6997
|
+
code_index: false,
|
|
6998
|
+
options: { type: "text", placeholder: "", lengthLimit: false, lengthMin: 0, lengthMax: 255 },
|
|
6999
|
+
transfers: null,
|
|
7000
|
+
children: null
|
|
7001
|
+
},
|
|
7002
|
+
{
|
|
7003
|
+
id: 1002,
|
|
7004
|
+
label: "\u6295\u7968\u63CF\u8FF0",
|
|
7005
|
+
type: "textarea",
|
|
7006
|
+
required: false,
|
|
7007
|
+
unique: false,
|
|
7008
|
+
editable: true,
|
|
7009
|
+
visible: true,
|
|
7010
|
+
show_label: true,
|
|
7011
|
+
scannable: false,
|
|
7012
|
+
default_value_mode: 0,
|
|
7013
|
+
description: "",
|
|
7014
|
+
value: null,
|
|
7015
|
+
number_decimal: 0,
|
|
7016
|
+
depends: [],
|
|
7017
|
+
key: "vote_description",
|
|
7018
|
+
code_index: false,
|
|
7019
|
+
options: { placeholder: "", html: false, size: "default", lengthLimit: false, lengthMin: 0, lengthMax: 2e3 },
|
|
7020
|
+
transfers: null,
|
|
7021
|
+
children: null
|
|
7022
|
+
}
|
|
7023
|
+
],
|
|
7024
|
+
options: { Buttons: [], CustomActions: [], FrontendEvents: [], TitleFormat: { Fields: [], Parts: [], Body: "" }, misc: {} },
|
|
7025
|
+
workflow_enabled: false
|
|
7026
|
+
};
|
|
7027
|
+
}
|
|
6855
7028
|
function isAssignUsersCommand(scope, command) {
|
|
6856
7029
|
return scope === "admin" && command.commandPath[0] === "access-rule" && command.commandPath[1] === "assign-users";
|
|
6857
7030
|
}
|
|
6858
|
-
function
|
|
7031
|
+
function isTableCreateCommand(scope, command) {
|
|
7032
|
+
return scope === "admin" && command.commandPath[0] === "table" && command.commandPath[1] === "create";
|
|
7033
|
+
}
|
|
7034
|
+
function isTableSchemaCommand(scope, command) {
|
|
7035
|
+
return scope === "admin" && command.commandPath[0] === "table" && (command.commandPath[1] === "create" || command.commandPath[1] === "update-schema");
|
|
7036
|
+
}
|
|
7037
|
+
function isAccessRuleCommand(scope, command) {
|
|
7038
|
+
return scope === "admin" && command.commandPath[0] === "access-rule";
|
|
7039
|
+
}
|
|
7040
|
+
function isAccessRuleUpdateCommand(scope, command) {
|
|
7041
|
+
return scope === "admin" && command.commandPath[0] === "access-rule" && command.commandPath[1] === "update";
|
|
7042
|
+
}
|
|
7043
|
+
function buildAccessRuleShapeHint(userId = 2188889901) {
|
|
7044
|
+
return buildHiddenFieldAccessRuleBody(userId);
|
|
7045
|
+
}
|
|
7046
|
+
function buildFullAccessRuleBody(userId = 2188889977) {
|
|
7047
|
+
return {
|
|
7048
|
+
name: "Admin full access",
|
|
7049
|
+
enabled: true,
|
|
7050
|
+
type: "form",
|
|
7051
|
+
options: {
|
|
7052
|
+
user_scope: [{ type: "user", id: userId }],
|
|
7053
|
+
policy: {
|
|
7054
|
+
key: "custom",
|
|
7055
|
+
actions: ["view", "add", "edit", "delete"],
|
|
7056
|
+
all_fields_read: true,
|
|
7057
|
+
all_fields_write: true
|
|
7058
|
+
},
|
|
7059
|
+
list_options: {}
|
|
7060
|
+
}
|
|
7061
|
+
};
|
|
7062
|
+
}
|
|
7063
|
+
function buildHiddenFieldAccessRuleBody(userId = 2188889901) {
|
|
7064
|
+
return {
|
|
7065
|
+
name: "Sales read write",
|
|
7066
|
+
enabled: true,
|
|
7067
|
+
type: "form",
|
|
7068
|
+
options: {
|
|
7069
|
+
user_scope: [{ type: "user", id: userId }],
|
|
7070
|
+
policy: {
|
|
7071
|
+
key: "custom",
|
|
7072
|
+
actions: ["view", "add", "edit"],
|
|
7073
|
+
all_fields_read: true,
|
|
7074
|
+
all_fields_write: true,
|
|
7075
|
+
fields: [{ key: ":1002", read: false, write: false, report: false }]
|
|
7076
|
+
},
|
|
7077
|
+
list_options: {}
|
|
7078
|
+
}
|
|
7079
|
+
};
|
|
7080
|
+
}
|
|
7081
|
+
function buildAccessRuleCreateToolCall(body) {
|
|
7082
|
+
return {
|
|
7083
|
+
command: "access-rule create",
|
|
7084
|
+
args: ["--app-id", "<app_id>", "--table-id", "<table_id>", "--body-json", JSON.stringify(body)]
|
|
7085
|
+
};
|
|
7086
|
+
}
|
|
7087
|
+
function buildAssignUsersValidationDetails(scope, command, requestType, path, message, env = process.env) {
|
|
6859
7088
|
return {
|
|
6860
7089
|
operation: `${scope}.${command.module}.${command.functionName}`,
|
|
6861
7090
|
requestType,
|
|
6862
|
-
issues: [{ path
|
|
7091
|
+
issues: [{ path, message }],
|
|
6863
7092
|
tsHints: [
|
|
6864
|
-
{ symbol: "AppIngressUpdateReqVO", file: "
|
|
6865
|
-
{ symbol: "EntityIngressOptions", file: "
|
|
6866
|
-
{ symbol: "PermitUserScope", file: "
|
|
7093
|
+
{ symbol: "AppIngressUpdateReqVO", file: sdkPath2("types/ingress.ts", env) },
|
|
7094
|
+
{ symbol: "EntityIngressOptions", file: sdkPath2("types/ingress.ts", env) },
|
|
7095
|
+
{ symbol: "PermitUserScope", file: sdkPath2("types/common.ts", env) }
|
|
6867
7096
|
],
|
|
6868
|
-
docHints: getDocHints(requestType),
|
|
7097
|
+
docHints: getDocHints(requestType, env),
|
|
6869
7098
|
shapeHint: {
|
|
6870
7099
|
update: ["user_scope"],
|
|
6871
7100
|
options: {
|
|
6872
|
-
user_scope: [{ type: "
|
|
7101
|
+
user_scope: [{ type: "user", id: 2188889901 }]
|
|
6873
7102
|
}
|
|
6874
7103
|
},
|
|
6875
7104
|
commonMistakes: [
|
|
@@ -6880,27 +7109,320 @@ function buildAssignUsersValidationDetails(scope, command, requestType, path2, m
|
|
|
6880
7109
|
]
|
|
6881
7110
|
};
|
|
6882
7111
|
}
|
|
6883
|
-
function
|
|
6884
|
-
if (
|
|
6885
|
-
|
|
7112
|
+
function buildBodyGuidance(requestType) {
|
|
7113
|
+
if (requestType === "EntitySaveReqVO" || requestType === "AppCreateEntityReqVO") {
|
|
7114
|
+
return {
|
|
7115
|
+
shapeHint: {
|
|
7116
|
+
id: 2188889845,
|
|
7117
|
+
app_id: 2188889844,
|
|
7118
|
+
name: "\u8BA2\u5355",
|
|
7119
|
+
schema_version: 0,
|
|
7120
|
+
field_id_seq: 1004,
|
|
7121
|
+
layout: [[1001], [1002], [1003]],
|
|
7122
|
+
fields: [
|
|
7123
|
+
{
|
|
7124
|
+
id: 1001,
|
|
7125
|
+
label: "\u8BA2\u5355\u53F7",
|
|
7126
|
+
type: "text",
|
|
7127
|
+
required: true,
|
|
7128
|
+
unique: false,
|
|
7129
|
+
editable: true,
|
|
7130
|
+
visible: true,
|
|
7131
|
+
show_label: true,
|
|
7132
|
+
scannable: false,
|
|
7133
|
+
default_value_mode: 0,
|
|
7134
|
+
description: "",
|
|
7135
|
+
value: null,
|
|
7136
|
+
number_decimal: 0,
|
|
7137
|
+
depends: [],
|
|
7138
|
+
key: "order_no",
|
|
7139
|
+
code_index: false,
|
|
7140
|
+
options: { type: "text", placeholder: "", lengthLimit: false, lengthMin: 0, lengthMax: 255 },
|
|
7141
|
+
transfers: null,
|
|
7142
|
+
children: null
|
|
7143
|
+
},
|
|
7144
|
+
{
|
|
7145
|
+
id: 1002,
|
|
7146
|
+
label: "\u63CF\u8FF0",
|
|
7147
|
+
type: "textarea",
|
|
7148
|
+
required: false,
|
|
7149
|
+
unique: false,
|
|
7150
|
+
editable: true,
|
|
7151
|
+
visible: true,
|
|
7152
|
+
show_label: true,
|
|
7153
|
+
scannable: false,
|
|
7154
|
+
default_value_mode: 0,
|
|
7155
|
+
description: "",
|
|
7156
|
+
value: null,
|
|
7157
|
+
number_decimal: 0,
|
|
7158
|
+
depends: [],
|
|
7159
|
+
key: "description",
|
|
7160
|
+
code_index: false,
|
|
7161
|
+
options: { placeholder: "", html: false, size: "default", lengthLimit: false, lengthMin: 0, lengthMax: 2e3 },
|
|
7162
|
+
transfers: null,
|
|
7163
|
+
children: null
|
|
7164
|
+
},
|
|
7165
|
+
{
|
|
7166
|
+
id: 1003,
|
|
7167
|
+
label: "\u72B6\u6001",
|
|
7168
|
+
type: "select",
|
|
7169
|
+
required: true,
|
|
7170
|
+
unique: false,
|
|
7171
|
+
editable: true,
|
|
7172
|
+
visible: true,
|
|
7173
|
+
show_label: true,
|
|
7174
|
+
scannable: false,
|
|
7175
|
+
default_value_mode: 1,
|
|
7176
|
+
description: "",
|
|
7177
|
+
value: "draft",
|
|
7178
|
+
number_decimal: 0,
|
|
7179
|
+
depends: [],
|
|
7180
|
+
key: "status",
|
|
7181
|
+
code_index: false,
|
|
7182
|
+
options: {
|
|
7183
|
+
horizontal: false,
|
|
7184
|
+
numberMax: "",
|
|
7185
|
+
numberMin: "",
|
|
7186
|
+
numberRange: false,
|
|
7187
|
+
repeatRemind: "This value already exists and duplicate submission is not allowed",
|
|
7188
|
+
options: {
|
|
7189
|
+
mode: "custom",
|
|
7190
|
+
colorful: false,
|
|
7191
|
+
items: [
|
|
7192
|
+
{ key: 1, value: "draft" },
|
|
7193
|
+
{ key: 2, value: "active" }
|
|
7194
|
+
]
|
|
7195
|
+
}
|
|
7196
|
+
},
|
|
7197
|
+
transfers: null,
|
|
7198
|
+
children: null
|
|
7199
|
+
}
|
|
7200
|
+
],
|
|
7201
|
+
options: { Buttons: [], CustomActions: [], FrontendEvents: [], TitleFormat: { Fields: [], Parts: [], Body: "" }, misc: {} },
|
|
7202
|
+
workflow_enabled: false
|
|
7203
|
+
},
|
|
7204
|
+
commonMistakes: [
|
|
7205
|
+
"table create must include fields and field_id_seq; do not create an empty table shell",
|
|
7206
|
+
"prefer --body-json for table create/update-schema; do not create a body file unless JSON is too large for one tool call",
|
|
7207
|
+
"fields must be an array of full FieldVO objects, not an object map",
|
|
7208
|
+
"get table shell first: arcubase-admin table get --app-id <app_id> --table-id <table_id>",
|
|
7209
|
+
"save the full returned schema after editing; do not submit only changed fields",
|
|
7210
|
+
"field_id_seq must be greater than every field.id",
|
|
7211
|
+
"layout must reference existing field ids",
|
|
7212
|
+
'use type "text", not "string"',
|
|
7213
|
+
'use type "member", not "user"',
|
|
7214
|
+
"for select/radio/checkbox/status, options must contain options.items",
|
|
7215
|
+
"for linkto/relation/query, options must contain relation.app_id, relation.entity_id, relation.type",
|
|
7216
|
+
"do not put per-user permissions in FieldVO; use access-rule for read/write and hidden fields"
|
|
7217
|
+
],
|
|
7218
|
+
suggestions: [
|
|
7219
|
+
`retry with: arcubase-admin table create --app-id <app_id> --body-json '${JSON.stringify(buildTableCreateExampleBody())}'`
|
|
7220
|
+
]
|
|
7221
|
+
};
|
|
7222
|
+
}
|
|
7223
|
+
if (requestType === "AppIngressCreateReqVO" || requestType === "AppIngressUpdateReqVO") {
|
|
7224
|
+
const retryToolCalls = [
|
|
7225
|
+
buildAccessRuleCreateToolCall(buildFullAccessRuleBody()),
|
|
7226
|
+
buildAccessRuleCreateToolCall(buildHiddenFieldAccessRuleBody())
|
|
7227
|
+
];
|
|
7228
|
+
return {
|
|
7229
|
+
retryToolCalls,
|
|
7230
|
+
suggestions: [
|
|
7231
|
+
"next arcubase-admin-cli input: retryToolCalls[0] for full access or retryToolCalls[1] for hidden-field access"
|
|
7232
|
+
],
|
|
7233
|
+
shapeHint: buildAccessRuleShapeHint(),
|
|
7234
|
+
commonMistakes: [
|
|
7235
|
+
"use options.policy, not top-level permissions",
|
|
7236
|
+
"use options.policy.fields, not field_visibility",
|
|
7237
|
+
"actions must use Arcubase action codes: view, add, edit; do not use read, write, or insert",
|
|
7238
|
+
'field permission keys must be strings prefixed with colon, for example ":1002"; do not use FieldVO.key values such as "vote_name"',
|
|
7239
|
+
'for access-rule update policy changes, use {"update":["options"],"options":{"policy":...,"list_options":{}}}; do not use update:["options.policy"]',
|
|
7240
|
+
'use options.user_scope with type user/department/actor and numeric id; do not use FieldVO type "member" here',
|
|
7241
|
+
"use assign-users only for updating user_scope later",
|
|
7242
|
+
'assign-users preserves existing policy when body.update=["user_scope"]'
|
|
7243
|
+
]
|
|
7244
|
+
};
|
|
7245
|
+
}
|
|
7246
|
+
if (requestType === "InsertReqVO") {
|
|
7247
|
+
return {
|
|
7248
|
+
shapeHint: {
|
|
7249
|
+
fields: {
|
|
7250
|
+
"1001": "SO-1001",
|
|
7251
|
+
"1002": 199
|
|
7252
|
+
}
|
|
7253
|
+
},
|
|
7254
|
+
commonMistakes: [
|
|
7255
|
+
"row fields must use numeric field ids as JSON object keys",
|
|
7256
|
+
'do not use field labels such as "\u6807\u9898" or "\u6295\u7968\u6807\u9898" as keys',
|
|
7257
|
+
"run table get first when field ids are unclear",
|
|
7258
|
+
"do not add access policy fields; the CLI resolves access policy internally"
|
|
7259
|
+
],
|
|
7260
|
+
suggestions: [
|
|
7261
|
+
"run: arcubase table get --app-id <app_id> --table-id <table_id>",
|
|
7262
|
+
`retry with: arcubase row create --app-id <app_id> --table-id <table_id> --body-json '{"fields":{"1001":"\u4ECA\u5929\u5403\u4EC0\u4E48"}}'`
|
|
7263
|
+
]
|
|
7264
|
+
};
|
|
7265
|
+
}
|
|
7266
|
+
if (requestType === "EntityQueryReqVO") {
|
|
7267
|
+
return {
|
|
7268
|
+
shapeHint: {
|
|
7269
|
+
limit: 20,
|
|
7270
|
+
offset: 0,
|
|
7271
|
+
search: { text_search: "SO-1001" }
|
|
7272
|
+
},
|
|
7273
|
+
commonMistakes: [
|
|
7274
|
+
"limit, offset, search, sorts, and view_mode belong inside --body-json",
|
|
7275
|
+
"do not pass --limit or --offset flags",
|
|
7276
|
+
"do not add access policy fields; the CLI resolves access policy internally"
|
|
7277
|
+
],
|
|
7278
|
+
suggestions: [
|
|
7279
|
+
`retry with: arcubase row query --app-id <app_id> --table-id <table_id> --body-json '{"limit":20,"offset":0}'`
|
|
7280
|
+
]
|
|
7281
|
+
};
|
|
7282
|
+
}
|
|
7283
|
+
if (requestType === "EntityUpdateReqVO") {
|
|
7284
|
+
return {
|
|
7285
|
+
shapeHint: {
|
|
7286
|
+
data: { "1002": 299 },
|
|
7287
|
+
changed_fields: [1002]
|
|
7288
|
+
},
|
|
7289
|
+
commonMistakes: [
|
|
7290
|
+
"use data, not fields",
|
|
7291
|
+
"changed_fields is required and must match data keys",
|
|
7292
|
+
"do not add access policy fields; the CLI resolves access policy internally"
|
|
7293
|
+
]
|
|
7294
|
+
};
|
|
7295
|
+
}
|
|
7296
|
+
if (requestType === "EntityBulkUpdateReqVO") {
|
|
7297
|
+
return {
|
|
7298
|
+
shapeHint: {
|
|
7299
|
+
selection: {
|
|
7300
|
+
type: "ids",
|
|
7301
|
+
ids: [2188890411, 2188890412],
|
|
7302
|
+
length: 2
|
|
7303
|
+
},
|
|
7304
|
+
fields: [
|
|
7305
|
+
{
|
|
7306
|
+
id: 1003,
|
|
7307
|
+
action: {
|
|
7308
|
+
type: "set",
|
|
7309
|
+
value: 2
|
|
7310
|
+
}
|
|
7311
|
+
}
|
|
7312
|
+
]
|
|
7313
|
+
},
|
|
7314
|
+
commonMistakes: [
|
|
7315
|
+
"bulk update fields[].action must be an object with type",
|
|
7316
|
+
'use {"type":"set","value":2} to assign a scalar value',
|
|
7317
|
+
"do not use value_set, setValue, or a top-level value field",
|
|
7318
|
+
'use {"type":"number_add","number_add":10} only for numeric increments',
|
|
7319
|
+
"selection.type=ids requires ids and length"
|
|
7320
|
+
],
|
|
7321
|
+
suggestions: [
|
|
7322
|
+
`retry with: arcubase row bulk-update --app-id <app_id> --table-id <table_id> --body-json '{"selection":{"type":"ids","ids":[2188890411],"length":1},"fields":[{"id":1003,"action":{"type":"set","value":2}}]}'`
|
|
7323
|
+
]
|
|
7324
|
+
};
|
|
6886
7325
|
}
|
|
6887
|
-
|
|
7326
|
+
return {};
|
|
7327
|
+
}
|
|
7328
|
+
function buildBodyValidationDetails(scope, command, requestType, issues, env = process.env) {
|
|
7329
|
+
return {
|
|
6888
7330
|
operation: `${scope}.${command.module}.${command.functionName}`,
|
|
6889
7331
|
requestType,
|
|
6890
|
-
issues
|
|
6891
|
-
|
|
6892
|
-
|
|
6893
|
-
|
|
6894
|
-
|
|
6895
|
-
|
|
6896
|
-
|
|
6897
|
-
|
|
6898
|
-
|
|
7332
|
+
issues,
|
|
7333
|
+
tsHints: getTypeHints(requestType, env),
|
|
7334
|
+
docHints: getDocHints(requestType, env),
|
|
7335
|
+
...buildBodyGuidance(requestType)
|
|
7336
|
+
};
|
|
7337
|
+
}
|
|
7338
|
+
function throwBodyValidationFailure(message, requestType, path, scope, command, env = process.env) {
|
|
7339
|
+
if (isAssignUsersCommand(scope, command)) {
|
|
7340
|
+
throw new CLIError("BODY_VALIDATION_FAILED", message, 2, buildAssignUsersValidationDetails(scope, command, requestType, path, message, env));
|
|
7341
|
+
}
|
|
7342
|
+
throw new CLIError("BODY_VALIDATION_FAILED", message, 2, buildBodyValidationDetails(scope, command, requestType, [{ path, message }], env));
|
|
7343
|
+
}
|
|
7344
|
+
function requireTableCreateSchemaBody(scope, command, body, env) {
|
|
7345
|
+
if (!isRecord2(body)) {
|
|
7346
|
+
throwBodyValidationFailure(
|
|
7347
|
+
"table create requires a JSON object with name, fields, field_id_seq, layout, options, and workflow_enabled",
|
|
7348
|
+
"AppCreateEntityReqVO",
|
|
7349
|
+
"body",
|
|
7350
|
+
scope,
|
|
7351
|
+
command,
|
|
7352
|
+
env
|
|
7353
|
+
);
|
|
7354
|
+
}
|
|
7355
|
+
if (!Array.isArray(body.fields) || body.fields.length === 0) {
|
|
7356
|
+
throwBodyValidationFailure(
|
|
7357
|
+
"table create must include non-empty body.fields; empty table shell creation is not allowed",
|
|
7358
|
+
"AppCreateEntityReqVO",
|
|
7359
|
+
"body.fields",
|
|
7360
|
+
scope,
|
|
7361
|
+
command,
|
|
7362
|
+
env
|
|
7363
|
+
);
|
|
7364
|
+
}
|
|
7365
|
+
if (typeof body.field_id_seq !== "number") {
|
|
7366
|
+
throwBodyValidationFailure(
|
|
7367
|
+
"table create must include body.field_id_seq greater than every field.id",
|
|
7368
|
+
"AppCreateEntityReqVO",
|
|
7369
|
+
"body.field_id_seq",
|
|
7370
|
+
scope,
|
|
7371
|
+
command,
|
|
7372
|
+
env
|
|
7373
|
+
);
|
|
7374
|
+
}
|
|
6899
7375
|
}
|
|
6900
7376
|
function stringArray(value) {
|
|
6901
7377
|
return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
6902
7378
|
}
|
|
6903
|
-
function
|
|
7379
|
+
function validateAccessRuleUserScope(scope, command, requestType, userScope, env, pathPrefix = "body.options.user_scope") {
|
|
7380
|
+
if (userScope === void 0) return;
|
|
7381
|
+
if (!Array.isArray(userScope)) {
|
|
7382
|
+
throwBodyValidationFailure(
|
|
7383
|
+
'access-rule user_scope must be an array of {"type":"user","id":2188889901}',
|
|
7384
|
+
requestType,
|
|
7385
|
+
pathPrefix,
|
|
7386
|
+
scope,
|
|
7387
|
+
command,
|
|
7388
|
+
env
|
|
7389
|
+
);
|
|
7390
|
+
}
|
|
7391
|
+
const allowedTypes = /* @__PURE__ */ new Set(["user", "department", "actor"]);
|
|
7392
|
+
for (const [index, item] of userScope.entries()) {
|
|
7393
|
+
if (!isRecord2(item)) {
|
|
7394
|
+
throwBodyValidationFailure(
|
|
7395
|
+
"access-rule user_scope item must be an object",
|
|
7396
|
+
requestType,
|
|
7397
|
+
`${pathPrefix}.${index}`,
|
|
7398
|
+
scope,
|
|
7399
|
+
command,
|
|
7400
|
+
env
|
|
7401
|
+
);
|
|
7402
|
+
}
|
|
7403
|
+
if (typeof item.type !== "string" || !allowedTypes.has(item.type)) {
|
|
7404
|
+
throwBodyValidationFailure(
|
|
7405
|
+
'access-rule user_scope[].type must be "user", "department", or "actor"; do not use FieldVO type "member" here',
|
|
7406
|
+
requestType,
|
|
7407
|
+
`${pathPrefix}.${index}.type`,
|
|
7408
|
+
scope,
|
|
7409
|
+
command,
|
|
7410
|
+
env
|
|
7411
|
+
);
|
|
7412
|
+
}
|
|
7413
|
+
if (typeof item.id !== "number" || !Number.isInteger(item.id) || item.id <= 0) {
|
|
7414
|
+
throwBodyValidationFailure(
|
|
7415
|
+
"access-rule user_scope[].id must be numeric TenantUser.ID, department ID, or actor ID",
|
|
7416
|
+
requestType,
|
|
7417
|
+
`${pathPrefix}.${index}.id`,
|
|
7418
|
+
scope,
|
|
7419
|
+
command,
|
|
7420
|
+
env
|
|
7421
|
+
);
|
|
7422
|
+
}
|
|
7423
|
+
}
|
|
7424
|
+
}
|
|
7425
|
+
function requireUpdateContains(scope, command, body, field, env) {
|
|
6904
7426
|
if (!(field in body)) return;
|
|
6905
7427
|
const update = stringArray(body.update);
|
|
6906
7428
|
if (!update.includes(field)) {
|
|
@@ -6909,34 +7431,132 @@ function requireUpdateContains(scope, command, body, field) {
|
|
|
6909
7431
|
command.requestType ?? "AppIngressUpdateReqVO",
|
|
6910
7432
|
"body.update",
|
|
6911
7433
|
scope,
|
|
6912
|
-
command
|
|
7434
|
+
command,
|
|
7435
|
+
env
|
|
6913
7436
|
);
|
|
6914
7437
|
}
|
|
6915
7438
|
}
|
|
6916
|
-
function validateActionSpecificRawBody(scope, command, body) {
|
|
7439
|
+
function validateActionSpecificRawBody(scope, command, body, env) {
|
|
6917
7440
|
if (!isRecord2(body) || !command.requestType) {
|
|
6918
7441
|
return;
|
|
6919
7442
|
}
|
|
6920
7443
|
if (isAssignUsersCommand(scope, command)) {
|
|
6921
7444
|
if ("users" in body || "allowedUsers" in body || "user_scope" in body) {
|
|
6922
7445
|
throwBodyValidationFailure(
|
|
6923
|
-
'access-rule assign-users only accepts body.options.user_scope with {"update":["user_scope"],"options":{"user_scope":[{"type":"
|
|
7446
|
+
'access-rule assign-users only accepts body.options.user_scope with {"update":["user_scope"],"options":{"user_scope":[{"type":"user","id":2188889901}]}}',
|
|
6924
7447
|
command.requestType,
|
|
6925
7448
|
"body.options.user_scope",
|
|
6926
7449
|
scope,
|
|
6927
|
-
command
|
|
7450
|
+
command,
|
|
7451
|
+
env
|
|
7452
|
+
);
|
|
7453
|
+
}
|
|
7454
|
+
}
|
|
7455
|
+
if (isTableSchemaCommand(scope, command)) {
|
|
7456
|
+
const fields = Array.isArray(body.fields) ? body.fields : [];
|
|
7457
|
+
const hasPermissionPatch = fields.some((field) => isRecord2(field) && ("permission" in field || "permissions" in field || "field_visibility" in field));
|
|
7458
|
+
if (hasPermissionPatch) {
|
|
7459
|
+
throwBodyValidationFailure(
|
|
7460
|
+
"table schema cannot configure per-user permissions. Use access-rule create/update with options.policy.fields for hidden fields",
|
|
7461
|
+
command.requestType,
|
|
7462
|
+
"body.fields",
|
|
7463
|
+
scope,
|
|
7464
|
+
command,
|
|
7465
|
+
env
|
|
6928
7466
|
);
|
|
6929
7467
|
}
|
|
6930
7468
|
}
|
|
7469
|
+
if (isAccessRuleCommand(scope, command)) {
|
|
7470
|
+
const update = stringArray(body.update);
|
|
7471
|
+
if (isAccessRuleUpdateCommand(scope, command) && update.some((item) => item.startsWith("options."))) {
|
|
7472
|
+
throwBodyValidationFailure(
|
|
7473
|
+
'access-rule update cannot patch nested options paths. Use {"update":["options"],"options":{"policy":{"key":"custom","actions":["view","add","edit"],"all_fields_read":true,"all_fields_write":true,"fields":[{"key":":1002","read":false,"write":false,"report":false}]},"list_options":{}}}',
|
|
7474
|
+
command.requestType,
|
|
7475
|
+
"body.update",
|
|
7476
|
+
scope,
|
|
7477
|
+
command,
|
|
7478
|
+
env
|
|
7479
|
+
);
|
|
7480
|
+
}
|
|
7481
|
+
if ("permissions" in body || "field_visibility" in body || "description" in body) {
|
|
7482
|
+
throwBodyValidationFailure(
|
|
7483
|
+
"access-rule body only supports name, enabled, type, and options; use options.policy.actions and options.policy.fields",
|
|
7484
|
+
command.requestType,
|
|
7485
|
+
"body",
|
|
7486
|
+
scope,
|
|
7487
|
+
command,
|
|
7488
|
+
env
|
|
7489
|
+
);
|
|
7490
|
+
}
|
|
7491
|
+
const options = isRecord2(body.options) ? body.options : void 0;
|
|
7492
|
+
if (options && ("permissions" in options || "field_visibility" in options)) {
|
|
7493
|
+
throwBodyValidationFailure(
|
|
7494
|
+
"access-rule options only supports user_scope, policy, list_options, i18n_name; use options.policy.actions and options.policy.fields",
|
|
7495
|
+
command.requestType,
|
|
7496
|
+
"body.options",
|
|
7497
|
+
scope,
|
|
7498
|
+
command,
|
|
7499
|
+
env
|
|
7500
|
+
);
|
|
7501
|
+
}
|
|
7502
|
+
const policy = options && isRecord2(options.policy) ? options.policy : void 0;
|
|
7503
|
+
if (isAccessRuleUpdateCommand(scope, command) && update.includes("options") && options?.user_scope !== void 0 && !policy) {
|
|
7504
|
+
throwBodyValidationFailure(
|
|
7505
|
+
'access-rule update with update:["options"] cannot change only options.user_scope because it overwrites policy. Use access-rule assign-users for user assignment, or include the full options.policy and options.list_options.',
|
|
7506
|
+
command.requestType,
|
|
7507
|
+
"body.options.policy",
|
|
7508
|
+
scope,
|
|
7509
|
+
command,
|
|
7510
|
+
env
|
|
7511
|
+
);
|
|
7512
|
+
}
|
|
7513
|
+
validateAccessRuleUserScope(scope, command, command.requestType, options?.user_scope, env);
|
|
7514
|
+
const actions = policy && Array.isArray(policy.actions) ? policy.actions : [];
|
|
7515
|
+
if (actions.includes("read") || actions.includes("write")) {
|
|
7516
|
+
throwBodyValidationFailure(
|
|
7517
|
+
'access-rule policy.actions must use Arcubase action codes: use "view" for read and "add","edit" for write; do not use "read", "write", or "insert"',
|
|
7518
|
+
command.requestType,
|
|
7519
|
+
"body.options.policy.actions",
|
|
7520
|
+
scope,
|
|
7521
|
+
command,
|
|
7522
|
+
env
|
|
7523
|
+
);
|
|
7524
|
+
}
|
|
7525
|
+
const fields = policy && Array.isArray(policy.fields) ? policy.fields : [];
|
|
7526
|
+
const allowedSystemFieldKeys = /* @__PURE__ */ new Set(["created", "updated", "creator"]);
|
|
7527
|
+
for (const [index, field] of fields.entries()) {
|
|
7528
|
+
if (!isRecord2(field)) continue;
|
|
7529
|
+
if (typeof field.key === "number" || typeof field.key === "string" && /^\d+$/.test(field.key)) {
|
|
7530
|
+
throwBodyValidationFailure(
|
|
7531
|
+
'access-rule policy.fields[].key must be a string prefixed with colon, for example ":1002"; do not use raw numbers',
|
|
7532
|
+
command.requestType,
|
|
7533
|
+
`body.options.policy.fields.${index}.key`,
|
|
7534
|
+
scope,
|
|
7535
|
+
command,
|
|
7536
|
+
env
|
|
7537
|
+
);
|
|
7538
|
+
}
|
|
7539
|
+
if (typeof field.key === "string" && !field.key.startsWith(":") && !allowedSystemFieldKeys.has(field.key)) {
|
|
7540
|
+
throwBodyValidationFailure(
|
|
7541
|
+
'access-rule policy.fields[].key must use Arcubase permission keys such as ":1002"; do not use FieldVO.key values such as "vote_name"',
|
|
7542
|
+
command.requestType,
|
|
7543
|
+
`body.options.policy.fields.${index}.key`,
|
|
7544
|
+
scope,
|
|
7545
|
+
command,
|
|
7546
|
+
env
|
|
7547
|
+
);
|
|
7548
|
+
}
|
|
7549
|
+
}
|
|
7550
|
+
}
|
|
6931
7551
|
}
|
|
6932
|
-
function validateActionSpecificBody(scope, command, flags, body) {
|
|
7552
|
+
function validateActionSpecificBody(scope, command, flags, body, env) {
|
|
6933
7553
|
if (!isRecord2(body) || !command.requestType) {
|
|
6934
7554
|
return;
|
|
6935
7555
|
}
|
|
6936
7556
|
if (scope === "admin" && command.commandPath[0] === "access-rule" && command.commandPath[1] === "update") {
|
|
6937
|
-
requireUpdateContains(scope, command, body, "enabled");
|
|
6938
|
-
requireUpdateContains(scope, command, body, "name");
|
|
6939
|
-
requireUpdateContains(scope, command, body, "options");
|
|
7557
|
+
requireUpdateContains(scope, command, body, "enabled", env);
|
|
7558
|
+
requireUpdateContains(scope, command, body, "name", env);
|
|
7559
|
+
requireUpdateContains(scope, command, body, "options", env);
|
|
6940
7560
|
}
|
|
6941
7561
|
if (isAssignUsersCommand(scope, command)) {
|
|
6942
7562
|
const update = stringArray(body.update);
|
|
@@ -6944,11 +7564,12 @@ function validateActionSpecificBody(scope, command, flags, body) {
|
|
|
6944
7564
|
const userScope = options && Array.isArray(options.user_scope) ? options.user_scope : void 0;
|
|
6945
7565
|
if ("users" in body || "allowedUsers" in body) {
|
|
6946
7566
|
throwBodyValidationFailure(
|
|
6947
|
-
'access-rule assign-users only accepts body.options.user_scope with {"update":["user_scope"],"options":{"user_scope":[{"type":"
|
|
7567
|
+
'access-rule assign-users only accepts body.options.user_scope with {"update":["user_scope"],"options":{"user_scope":[{"type":"user","id":2188889901}]}}',
|
|
6948
7568
|
command.requestType,
|
|
6949
7569
|
"body.options.user_scope",
|
|
6950
7570
|
scope,
|
|
6951
|
-
command
|
|
7571
|
+
command,
|
|
7572
|
+
env
|
|
6952
7573
|
);
|
|
6953
7574
|
}
|
|
6954
7575
|
if (!update.includes("user_scope")) {
|
|
@@ -6957,7 +7578,8 @@ function validateActionSpecificBody(scope, command, flags, body) {
|
|
|
6957
7578
|
command.requestType,
|
|
6958
7579
|
"body.update",
|
|
6959
7580
|
scope,
|
|
6960
|
-
command
|
|
7581
|
+
command,
|
|
7582
|
+
env
|
|
6961
7583
|
);
|
|
6962
7584
|
}
|
|
6963
7585
|
if (!userScope || userScope.length === 0) {
|
|
@@ -6966,9 +7588,11 @@ function validateActionSpecificBody(scope, command, flags, body) {
|
|
|
6966
7588
|
command.requestType,
|
|
6967
7589
|
"body.options.user_scope",
|
|
6968
7590
|
scope,
|
|
6969
|
-
command
|
|
7591
|
+
command,
|
|
7592
|
+
env
|
|
6970
7593
|
);
|
|
6971
7594
|
}
|
|
7595
|
+
validateAccessRuleUserScope(scope, command, command.requestType, userScope, env);
|
|
6972
7596
|
const assignedUserScope = userScope;
|
|
6973
7597
|
for (const [index, item] of assignedUserScope.entries()) {
|
|
6974
7598
|
if (!isRecord2(item)) {
|
|
@@ -6977,16 +7601,18 @@ function validateActionSpecificBody(scope, command, flags, body) {
|
|
|
6977
7601
|
command.requestType,
|
|
6978
7602
|
`body.options.user_scope.${index}`,
|
|
6979
7603
|
scope,
|
|
6980
|
-
command
|
|
7604
|
+
command,
|
|
7605
|
+
env
|
|
6981
7606
|
);
|
|
6982
7607
|
}
|
|
6983
|
-
if (item.type !== "
|
|
7608
|
+
if (item.type !== "user") {
|
|
6984
7609
|
throwBodyValidationFailure(
|
|
6985
|
-
'access-rule assign-users requires body.options.user_scope[].type to be "
|
|
7610
|
+
'access-rule assign-users requires body.options.user_scope[].type to be "user"',
|
|
6986
7611
|
command.requestType,
|
|
6987
7612
|
`body.options.user_scope.${index}.type`,
|
|
6988
7613
|
scope,
|
|
6989
|
-
command
|
|
7614
|
+
command,
|
|
7615
|
+
env
|
|
6990
7616
|
);
|
|
6991
7617
|
}
|
|
6992
7618
|
if (typeof item.id !== "number" || !Number.isInteger(item.id) || item.id <= 0) {
|
|
@@ -6995,7 +7621,8 @@ function validateActionSpecificBody(scope, command, flags, body) {
|
|
|
6995
7621
|
command.requestType,
|
|
6996
7622
|
`body.options.user_scope.${index}.id`,
|
|
6997
7623
|
scope,
|
|
6998
|
-
command
|
|
7624
|
+
command,
|
|
7625
|
+
env
|
|
6999
7626
|
);
|
|
7000
7627
|
}
|
|
7001
7628
|
}
|
|
@@ -7016,7 +7643,8 @@ function validateActionSpecificBody(scope, command, flags, body) {
|
|
|
7016
7643
|
command.requestType,
|
|
7017
7644
|
"body.selection.type",
|
|
7018
7645
|
scope,
|
|
7019
|
-
command
|
|
7646
|
+
command,
|
|
7647
|
+
env
|
|
7020
7648
|
);
|
|
7021
7649
|
}
|
|
7022
7650
|
return;
|
|
@@ -7027,7 +7655,8 @@ function validateActionSpecificBody(scope, command, flags, body) {
|
|
|
7027
7655
|
command.requestType,
|
|
7028
7656
|
"body.selection.type",
|
|
7029
7657
|
scope,
|
|
7030
|
-
command
|
|
7658
|
+
command,
|
|
7659
|
+
env
|
|
7031
7660
|
);
|
|
7032
7661
|
}
|
|
7033
7662
|
if ((action === "archive" || action === "delete") && type === "condition" && conditionKeys.length === 0) {
|
|
@@ -7036,38 +7665,353 @@ function validateActionSpecificBody(scope, command, flags, body) {
|
|
|
7036
7665
|
command.requestType,
|
|
7037
7666
|
"body.selection.condition",
|
|
7038
7667
|
scope,
|
|
7039
|
-
command
|
|
7668
|
+
command,
|
|
7669
|
+
env
|
|
7040
7670
|
);
|
|
7041
7671
|
}
|
|
7042
7672
|
}
|
|
7043
7673
|
}
|
|
7044
|
-
|
|
7045
|
-
|
|
7046
|
-
|
|
7047
|
-
if (
|
|
7048
|
-
|
|
7049
|
-
|
|
7050
|
-
|
|
7051
|
-
|
|
7052
|
-
|
|
7053
|
-
|
|
7054
|
-
|
|
7055
|
-
|
|
7056
|
-
|
|
7057
|
-
|
|
7058
|
-
|
|
7059
|
-
|
|
7060
|
-
|
|
7061
|
-
|
|
7062
|
-
|
|
7063
|
-
|
|
7674
|
+
function unwrapData(value) {
|
|
7675
|
+
let current = value;
|
|
7676
|
+
for (let i = 0; i < 3; i += 1) {
|
|
7677
|
+
if (isRecord2(current) && isRecord2(current.data)) {
|
|
7678
|
+
current = current.data;
|
|
7679
|
+
continue;
|
|
7680
|
+
}
|
|
7681
|
+
break;
|
|
7682
|
+
}
|
|
7683
|
+
return current;
|
|
7684
|
+
}
|
|
7685
|
+
function numericFieldKeys(fields) {
|
|
7686
|
+
if (!isRecord2(fields)) return [];
|
|
7687
|
+
return Object.keys(fields).filter((key) => /^\d+$/.test(key)).sort((left, right) => Number(left) - Number(right));
|
|
7688
|
+
}
|
|
7689
|
+
function permitFieldId(permit) {
|
|
7690
|
+
if (!isRecord2(permit) || typeof permit.key !== "string") return void 0;
|
|
7691
|
+
const match = /^:(\d+)$/.exec(permit.key);
|
|
7692
|
+
return match?.[1];
|
|
7693
|
+
}
|
|
7694
|
+
function rowFieldPermits(value) {
|
|
7695
|
+
const data = unwrapData(value);
|
|
7696
|
+
const fieldPermits = isRecord2(data) && isRecord2(data.fieldPermits) ? data.fieldPermits : void 0;
|
|
7697
|
+
return fieldPermits && Array.isArray(fieldPermits.fields) ? fieldPermits.fields.filter((item) => isRecord2(item)) : [];
|
|
7698
|
+
}
|
|
7699
|
+
function buildRowValueEvidence(command, responseBody) {
|
|
7700
|
+
if (command.scope !== "user" || command.commandPath[0] !== "row") return void 0;
|
|
7701
|
+
const action = command.commandPath[1];
|
|
7702
|
+
const data = unwrapData(responseBody);
|
|
7703
|
+
const rules = [
|
|
7704
|
+
"current row values come only from row query fields or row get record.fields",
|
|
7705
|
+
"table schema fields[].value and default_value_mode are schema defaults, not returned row values",
|
|
7706
|
+
"a field id absent from returned row fields has no row-value evidence",
|
|
7707
|
+
"read visibility status is fieldPermits read:false; FIELD_PERMISSION_REQUIRED is only a write preflight error"
|
|
7708
|
+
];
|
|
7709
|
+
if (action === "get") {
|
|
7710
|
+
const record = isRecord2(data) && isRecord2(data.record) ? data.record : void 0;
|
|
7711
|
+
const returnedFieldIds = numericFieldKeys(record?.fields);
|
|
7712
|
+
const permits = rowFieldPermits(responseBody);
|
|
7713
|
+
const permitFieldIds = permits.map(permitFieldId).filter((id) => Boolean(id));
|
|
7714
|
+
const deniedReadFieldIds = permits.filter((permit) => permit.read === false).map(permitFieldId).filter((id) => Boolean(id)).sort((left, right) => Number(left) - Number(right));
|
|
7715
|
+
const notReturnedFieldIds = permitFieldIds.filter((id) => !returnedFieldIds.includes(id)).sort((left, right) => Number(left) - Number(right));
|
|
7064
7716
|
return {
|
|
7065
|
-
|
|
7066
|
-
|
|
7067
|
-
|
|
7068
|
-
|
|
7717
|
+
source: "row get record.fields",
|
|
7718
|
+
returnedFieldIds,
|
|
7719
|
+
notReturnedFieldIds,
|
|
7720
|
+
deniedReadFieldIds,
|
|
7721
|
+
absentFieldMeaning: "not returned to current user; no row-value evidence",
|
|
7722
|
+
rules
|
|
7069
7723
|
};
|
|
7070
7724
|
}
|
|
7725
|
+
if (action === "query") {
|
|
7726
|
+
const items = isRecord2(data) && Array.isArray(data.items) ? data.items : [];
|
|
7727
|
+
return {
|
|
7728
|
+
source: "row query items[].fields",
|
|
7729
|
+
rows: items.filter((item) => isRecord2(item)).map((item) => ({
|
|
7730
|
+
rowId: item.id,
|
|
7731
|
+
returnedFieldIds: numericFieldKeys(item.fields)
|
|
7732
|
+
})),
|
|
7733
|
+
absentFieldMeaning: "not returned to current user; no row-value evidence",
|
|
7734
|
+
rules
|
|
7735
|
+
};
|
|
7736
|
+
}
|
|
7737
|
+
return void 0;
|
|
7738
|
+
}
|
|
7739
|
+
function requiredRowAction(command, flags) {
|
|
7740
|
+
if (command.commandPath[0] !== "row") return void 0;
|
|
7741
|
+
switch (command.commandPath[1]) {
|
|
7742
|
+
case "query":
|
|
7743
|
+
case "get":
|
|
7744
|
+
return "view";
|
|
7745
|
+
case "create":
|
|
7746
|
+
return "add";
|
|
7747
|
+
case "update":
|
|
7748
|
+
return "edit";
|
|
7749
|
+
case "delete":
|
|
7750
|
+
return "delete";
|
|
7751
|
+
case "bulk-update":
|
|
7752
|
+
return "bulk_update";
|
|
7753
|
+
case "selection-action":
|
|
7754
|
+
return flagValue(flags, "action") || void 0;
|
|
7755
|
+
default:
|
|
7756
|
+
return void 0;
|
|
7757
|
+
}
|
|
7758
|
+
}
|
|
7759
|
+
function rowCommandNeedsPolicy(command) {
|
|
7760
|
+
return command.scope === "user" && command.commandPath[0] === "row";
|
|
7761
|
+
}
|
|
7762
|
+
function extractIngressItems(appDetail) {
|
|
7763
|
+
const appData = unwrapData(appDetail);
|
|
7764
|
+
const ingress = isRecord2(appData) ? appData.ingress : void 0;
|
|
7765
|
+
const groups = isRecord2(ingress) && Array.isArray(ingress.groups) ? ingress.groups : [];
|
|
7766
|
+
const items = [];
|
|
7767
|
+
for (const group of groups) {
|
|
7768
|
+
const groupItems = isRecord2(group) && Array.isArray(group.items) ? group.items : [];
|
|
7769
|
+
for (const item of groupItems) {
|
|
7770
|
+
if (!isRecord2(item)) continue;
|
|
7771
|
+
const id = typeof item.id === "string" ? item.id : typeof item.ID === "string" ? item.ID : "";
|
|
7772
|
+
if (id) {
|
|
7773
|
+
items.push({ id });
|
|
7774
|
+
}
|
|
7775
|
+
}
|
|
7776
|
+
}
|
|
7777
|
+
return items;
|
|
7778
|
+
}
|
|
7779
|
+
function ingressMatchesTableAndAction(ingressDetail, tableId, action) {
|
|
7780
|
+
const ingressData = unwrapData(ingressDetail);
|
|
7781
|
+
if (!isRecord2(ingressData)) return void 0;
|
|
7782
|
+
const id = typeof ingressData.id === "number" || typeof ingressData.id === "string" ? ingressData.id : typeof ingressData.ID === "number" || typeof ingressData.ID === "string" ? ingressData.ID : void 0;
|
|
7783
|
+
if (String(id ?? "") !== tableId) return void 0;
|
|
7784
|
+
const policyID = typeof ingressData.hash_id === "string" ? ingressData.hash_id : typeof ingressData.hashId === "string" ? ingressData.hashId : void 0;
|
|
7785
|
+
const policy = isRecord2(ingressData.policy) ? ingressData.policy : void 0;
|
|
7786
|
+
if (!action) return { policyID: policyID || "", policy };
|
|
7787
|
+
const actions = policy && Array.isArray(policy.actions) ? policy.actions.filter((item) => typeof item === "string") : [];
|
|
7788
|
+
if (!actions.includes(action)) return void 0;
|
|
7789
|
+
return { policyID: policyID || "", policy };
|
|
7790
|
+
}
|
|
7791
|
+
function writtenRowFieldIds(command, body) {
|
|
7792
|
+
if (!isRecord2(body)) return [];
|
|
7793
|
+
const source = command.commandPath[1] === "create" ? body.fields : command.commandPath[1] === "update" ? body.data : void 0;
|
|
7794
|
+
if (!isRecord2(source)) return [];
|
|
7795
|
+
return Object.keys(source).filter((key) => /^\d+$/.test(key)).map((key) => Number(key));
|
|
7796
|
+
}
|
|
7797
|
+
function fieldWriteAllowedByPolicy(policy, fieldId) {
|
|
7798
|
+
if (!policy) return true;
|
|
7799
|
+
const fields = Array.isArray(policy.fields) ? policy.fields : [];
|
|
7800
|
+
const explicit = fields.find((item) => isRecord2(item) && item.key === `:${fieldId}`);
|
|
7801
|
+
if (isRecord2(explicit) && explicit.write === false) return false;
|
|
7802
|
+
if (isRecord2(explicit) && explicit.write === true) return true;
|
|
7803
|
+
if (policy.all_fields_write === false) return false;
|
|
7804
|
+
return true;
|
|
7805
|
+
}
|
|
7806
|
+
function assertWritableFieldsForRowCommand(command, runtimeEnv, body, policy) {
|
|
7807
|
+
if (command.commandPath[1] !== "create" && command.commandPath[1] !== "update") {
|
|
7808
|
+
return;
|
|
7809
|
+
}
|
|
7810
|
+
const denied = writtenRowFieldIds(command, body).filter((fieldId) => !fieldWriteAllowedByPolicy(policy, fieldId));
|
|
7811
|
+
if (denied.length === 0) {
|
|
7812
|
+
return;
|
|
7813
|
+
}
|
|
7814
|
+
const payloadKey = command.commandPath[1] === "create" ? "fields" : "data";
|
|
7815
|
+
throw new CLIError("FIELD_PERMISSION_REQUIRED", `row ${command.commandPath[1]} includes field ids without write permission: ${denied.join(", ")}`, 2, {
|
|
7816
|
+
operation: `user.${command.module}.${command.functionName}`,
|
|
7817
|
+
requestType: command.requestType ?? void 0,
|
|
7818
|
+
issues: denied.map((fieldId) => ({
|
|
7819
|
+
path: `body.${payloadKey}.${fieldId}`,
|
|
7820
|
+
message: "field is not writable for the resolved Arcubase access rule"
|
|
7821
|
+
})),
|
|
7822
|
+
docHints: [
|
|
7823
|
+
{ title: "Row CRUD", file: sdkPath2("docs/runtime-reference/row-crud.md", runtimeEnv) },
|
|
7824
|
+
{ title: "Runtime reference", file: sdkPath2("docs/runtime-reference/README.md", runtimeEnv) }
|
|
7825
|
+
],
|
|
7826
|
+
suggestions: [
|
|
7827
|
+
"remove non-writable field ids from the row body and retry",
|
|
7828
|
+
"run arcubase table get to map visible business fields to numeric field ids",
|
|
7829
|
+
"ask an admin to update the access-rule if this field should be writable"
|
|
7830
|
+
]
|
|
7831
|
+
});
|
|
7832
|
+
}
|
|
7833
|
+
async function resolvePolicyIDForRowCommand(command, runtimeEnv, flags, fetchImpl) {
|
|
7834
|
+
const appId = flagValue(flags, "app-id");
|
|
7835
|
+
const tableId = flagValue(flags, "table-id");
|
|
7836
|
+
const action = requiredRowAction(command, flags);
|
|
7837
|
+
if (!appId || !tableId) {
|
|
7838
|
+
throw new CLIError("POLICY_ID_RESOLUTION_FAILED", "row command requires --app-id and --table-id to resolve Arcubase policy_id", 2, {
|
|
7839
|
+
operation: `user.${command.module}.${command.functionName}`,
|
|
7840
|
+
docHints: getDocHints(command.requestType ?? "", runtimeEnv)
|
|
7841
|
+
});
|
|
7842
|
+
}
|
|
7843
|
+
const appDetail = await requestJSON(runtimeEnv, "GET", `/api/apps/${encodeURIComponent(appId)}`, void 0, fetchImpl);
|
|
7844
|
+
const ingressItems = extractIngressItems(appDetail.data);
|
|
7845
|
+
for (const item of ingressItems) {
|
|
7846
|
+
const ingressDetail = await requestJSON(runtimeEnv, "GET", `/api/ingress/${encodeURIComponent(appId)}/${encodeURIComponent(item.id)}`, void 0, fetchImpl);
|
|
7847
|
+
const match = ingressMatchesTableAndAction(ingressDetail.data, tableId, action);
|
|
7848
|
+
if (match) {
|
|
7849
|
+
return { ...match, policyID: match.policyID || item.id };
|
|
7850
|
+
}
|
|
7851
|
+
}
|
|
7852
|
+
throw new CLIError("POLICY_ID_RESOLUTION_FAILED", `no accessible ingress policy found for app ${appId}, table ${tableId}${action ? `, action ${action}` : ""}`, 2, {
|
|
7853
|
+
operation: `user.${command.module}.${command.functionName}`,
|
|
7854
|
+
requestType: command.requestType ?? void 0,
|
|
7855
|
+
issues: [{ path: "policy_id", message: "CLI could not resolve policy_id from accessible ingress" }],
|
|
7856
|
+
docHints: [
|
|
7857
|
+
{ title: "Row CRUD", file: sdkPath2("docs/runtime-reference/row-crud.md", runtimeEnv) },
|
|
7858
|
+
{ title: "Runtime reference", file: sdkPath2("docs/runtime-reference/README.md", runtimeEnv) }
|
|
7859
|
+
],
|
|
7860
|
+
suggestions: [
|
|
7861
|
+
"run arcubase entry and confirm the app/table is visible",
|
|
7862
|
+
"ask an admin to create an enabled access-rule with the required action for this table"
|
|
7863
|
+
]
|
|
7864
|
+
});
|
|
7865
|
+
}
|
|
7866
|
+
async function injectResolvedPolicyID(command, runtimeEnv, flags, query, body, fetchImpl) {
|
|
7867
|
+
if (!rowCommandNeedsPolicy(command)) {
|
|
7868
|
+
return { query, body };
|
|
7869
|
+
}
|
|
7870
|
+
if (typeof query.policy_id === "string" && query.policy_id) {
|
|
7871
|
+
return { query, body };
|
|
7872
|
+
}
|
|
7873
|
+
if (isRecord2(body) && typeof body.policy_id === "string" && body.policy_id) {
|
|
7874
|
+
return { query, body };
|
|
7875
|
+
}
|
|
7876
|
+
const resolvedPolicy = await resolvePolicyIDForRowCommand(command, runtimeEnv, flags, fetchImpl);
|
|
7877
|
+
const policyID = resolvedPolicy.policyID;
|
|
7878
|
+
assertWritableFieldsForRowCommand(command, runtimeEnv, body, resolvedPolicy.policy);
|
|
7879
|
+
if (command.commandPath[1] === "get") {
|
|
7880
|
+
return { query: { ...query, policy_id: policyID }, body };
|
|
7881
|
+
}
|
|
7882
|
+
if (isRecord2(body)) {
|
|
7883
|
+
return { query, body: { ...body, policy_id: policyID } };
|
|
7884
|
+
}
|
|
7885
|
+
return { query, body };
|
|
7886
|
+
}
|
|
7887
|
+
function assertNoUserPolicyIDInput(command, runtimeEnv, query, body) {
|
|
7888
|
+
if (!rowCommandNeedsPolicy(command)) {
|
|
7889
|
+
return;
|
|
7890
|
+
}
|
|
7891
|
+
if ("policy_id" in query || isRecord2(body) && "policy_id" in body) {
|
|
7892
|
+
throw new CLIError("INTERNAL_POLICY_ID_NOT_ALLOWED", "policy_id is an internal Arcubase ingress parameter; use app/table/row ids only", 2, {
|
|
7893
|
+
operation: `user.${command.module}.${command.functionName}`,
|
|
7894
|
+
issues: [{ path: "policy_id", message: "do not provide policy_id in flags, query file, or body JSON" }],
|
|
7895
|
+
docHints: [
|
|
7896
|
+
{ title: "Row CRUD", file: sdkPath2("docs/runtime-reference/row-crud.md", runtimeEnv) },
|
|
7897
|
+
{ title: "Runtime reference", file: sdkPath2("docs/runtime-reference/README.md", runtimeEnv) }
|
|
7898
|
+
],
|
|
7899
|
+
suggestions: ["run arcubase entry to find the app/table ids, then retry without policy_id"]
|
|
7900
|
+
});
|
|
7901
|
+
}
|
|
7902
|
+
}
|
|
7903
|
+
async function requestJSON(runtimeEnv, method, endpoint, body, fetchImpl) {
|
|
7904
|
+
const response = await fetchUpstream(buildURL(runtimeEnv.ARCUBASE_BASE_URL, endpoint), {
|
|
7905
|
+
method,
|
|
7906
|
+
headers: {
|
|
7907
|
+
...buildRequestHeaders(runtimeEnv),
|
|
7908
|
+
"Content-Type": "application/json"
|
|
7909
|
+
},
|
|
7910
|
+
body: body === void 0 || method === "GET" ? void 0 : JSON.stringify(body)
|
|
7911
|
+
}, endpoint, method, fetchImpl);
|
|
7912
|
+
const raw = await response.text();
|
|
7913
|
+
let parsedResponse = raw;
|
|
7914
|
+
try {
|
|
7915
|
+
parsedResponse = raw ? JSON.parse(raw) : null;
|
|
7916
|
+
} catch {
|
|
7917
|
+
}
|
|
7918
|
+
if (!response.ok) {
|
|
7919
|
+
throwUpstreamHTTPError(endpoint, method, response, parsedResponse);
|
|
7920
|
+
}
|
|
7921
|
+
if (parsedResponse && typeof parsedResponse === "object" && "error" in parsedResponse && parsedResponse.error) {
|
|
7922
|
+
const upstreamError = parsedResponse.error;
|
|
7923
|
+
const upstreamMessage = upstreamErrorMessage(upstreamError);
|
|
7924
|
+
throw new CLIError("UPSTREAM_BODY_ERROR", upstreamMessage, 1, { upstreamError });
|
|
7925
|
+
}
|
|
7926
|
+
return { status: response.status, data: parsedResponse };
|
|
7927
|
+
}
|
|
7928
|
+
function extractCreatedTableID(value) {
|
|
7929
|
+
const candidates = [
|
|
7930
|
+
value,
|
|
7931
|
+
isRecord2(value) ? value.data : void 0,
|
|
7932
|
+
isRecord2(value) && isRecord2(value.data) ? value.data.data : void 0
|
|
7933
|
+
];
|
|
7934
|
+
for (const candidate of candidates) {
|
|
7935
|
+
if (isRecord2(candidate) && typeof candidate.id === "number") {
|
|
7936
|
+
return candidate.id;
|
|
7937
|
+
}
|
|
7938
|
+
}
|
|
7939
|
+
throw new CLIError("UPSTREAM_RESPONSE_INVALID", "table create response did not include numeric table id", 1);
|
|
7940
|
+
}
|
|
7941
|
+
function normalizeTableCreateSchemaBody(body, appId, tableId) {
|
|
7942
|
+
const { parent: _parent, ...schemaBody } = body;
|
|
7943
|
+
return {
|
|
7944
|
+
...schemaBody,
|
|
7945
|
+
id: tableId,
|
|
7946
|
+
app_id: Number.isFinite(Number(appId)) ? Number(appId) : body.app_id,
|
|
7947
|
+
schema_version: typeof body.schema_version === "number" ? body.schema_version : 0,
|
|
7948
|
+
layout: Array.isArray(body.layout) ? body.layout : [],
|
|
7949
|
+
options: isRecord2(body.options) ? body.options : { Buttons: [], CustomActions: [], FrontendEvents: [], TitleFormat: { Fields: [], Parts: [], Body: "" }, misc: {} },
|
|
7950
|
+
workflow_enabled: typeof body.workflow_enabled === "boolean" ? body.workflow_enabled : false
|
|
7951
|
+
};
|
|
7952
|
+
}
|
|
7953
|
+
async function executeTableCreateWithSchema(command, runtimeEnv, flags, body, fetchImpl) {
|
|
7954
|
+
const appId = flagValue(flags, "app-id");
|
|
7955
|
+
if (!appId) {
|
|
7956
|
+
throw new CLIError("MISSING_PATH_FLAG", "missing required flag --app-id", 2);
|
|
7957
|
+
}
|
|
7958
|
+
if (!isRecord2(body)) {
|
|
7959
|
+
throw new CLIError("BODY_VALIDATION_FAILED", "table create body must be an object", 2);
|
|
7960
|
+
}
|
|
7961
|
+
const createBody = {
|
|
7962
|
+
name: typeof body.name === "string" ? body.name : void 0,
|
|
7963
|
+
parent: typeof body.parent === "number" ? body.parent : 0
|
|
7964
|
+
};
|
|
7965
|
+
if (!createBody.name) {
|
|
7966
|
+
throw new CLIError("BODY_VALIDATION_FAILED", "table create requires body.name", 2);
|
|
7967
|
+
}
|
|
7968
|
+
const createResult = await requestJSON(runtimeEnv, command.method, resolveEndpoint(command, flags), createBody, fetchImpl);
|
|
7969
|
+
const tableId = extractCreatedTableID(createResult.data);
|
|
7970
|
+
const saveBody = normalizeTableCreateSchemaBody(body, appId, tableId);
|
|
7971
|
+
const saveSchema = getBodySchema("EntitySaveReqVO");
|
|
7972
|
+
if (!saveSchema) {
|
|
7973
|
+
throw new CLIError("BODY_VALIDATION_FAILED", "EntitySaveReqVO schema is not available", 2);
|
|
7974
|
+
}
|
|
7975
|
+
const parsedSaveBody = saveSchema.safeParse(saveBody);
|
|
7976
|
+
if (!parsedSaveBody.success) {
|
|
7977
|
+
const message = parsedSaveBody.error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`).join("; ");
|
|
7978
|
+
throw new CLIError(
|
|
7979
|
+
"BODY_VALIDATION_FAILED",
|
|
7980
|
+
message,
|
|
7981
|
+
2,
|
|
7982
|
+
buildBodyValidationDetails(
|
|
7983
|
+
"admin",
|
|
7984
|
+
command,
|
|
7985
|
+
"EntitySaveReqVO",
|
|
7986
|
+
parsedSaveBody.error.issues.map((issue) => ({
|
|
7987
|
+
path: issue.path.length > 0 ? `body.${issue.path.join(".")}` : "body",
|
|
7988
|
+
message: issue.message
|
|
7989
|
+
})),
|
|
7990
|
+
runtimeEnv
|
|
7991
|
+
)
|
|
7992
|
+
);
|
|
7993
|
+
}
|
|
7994
|
+
const saveResult = await requestJSON(
|
|
7995
|
+
runtimeEnv,
|
|
7996
|
+
"PUT",
|
|
7997
|
+
`/api/apps/${encodeURIComponent(appId)}/entity/${encodeURIComponent(String(tableId))}`,
|
|
7998
|
+
parsedSaveBody.data,
|
|
7999
|
+
fetchImpl
|
|
8000
|
+
);
|
|
8001
|
+
return {
|
|
8002
|
+
kind: "result",
|
|
8003
|
+
commandPath: command.commandPath,
|
|
8004
|
+
status: saveResult.status,
|
|
8005
|
+
data: {
|
|
8006
|
+
id: tableId,
|
|
8007
|
+
created: createResult.data,
|
|
8008
|
+
schema: saveResult.data
|
|
8009
|
+
}
|
|
8010
|
+
};
|
|
8011
|
+
}
|
|
8012
|
+
async function executeCLI(scope, argv, env, fetchImpl = fetch) {
|
|
8013
|
+
const parsed = parseCLIArgs(argv);
|
|
8014
|
+
const envInput = env ?? process.env;
|
|
7071
8015
|
if (parsed.commandTokens.length === 0) {
|
|
7072
8016
|
return { kind: "help", text: renderRootHelp(scope) };
|
|
7073
8017
|
}
|
|
@@ -7077,30 +8021,69 @@ async function executeCLI(scope, argv, env, fetchImpl = fetch) {
|
|
|
7077
8021
|
}
|
|
7078
8022
|
const singleTokenCommand = !commandName ? findCommand(scope, moduleName) : null;
|
|
7079
8023
|
if (!commandName && !singleTokenCommand) {
|
|
7080
|
-
return { kind: "help", text: renderModuleHelp(scope, moduleName) };
|
|
8024
|
+
return { kind: "help", text: renderModuleHelp(scope, moduleName, envInput) };
|
|
7081
8025
|
}
|
|
7082
8026
|
if (hasFlag(parsed.flags, "help")) {
|
|
7083
|
-
return { kind: "help", text: renderCommandHelp(scope, moduleName, commandName) };
|
|
8027
|
+
return { kind: "help", text: renderCommandHelp(scope, moduleName, commandName, envInput) };
|
|
7084
8028
|
}
|
|
7085
|
-
const runtimeEnv = env ?? loadRuntimeEnv(scope);
|
|
7086
8029
|
const command = findCommand(scope, moduleName, commandName);
|
|
7087
8030
|
if (!command) {
|
|
7088
8031
|
throw new CLIError("UNKNOWN_COMMAND", `unknown command: ${moduleName}${commandName ? ` ${commandName}` : ""}`, 2, buildUnknownCommandDetails(scope, moduleName, commandName ?? ""));
|
|
7089
8032
|
}
|
|
8033
|
+
validateKnownFlags(command, parsed.flags, envInput);
|
|
8034
|
+
const runtimeEnv = env ?? loadRuntimeEnv(scope);
|
|
7090
8035
|
const endpoint = resolveEndpoint(command, parsed.flags);
|
|
7091
8036
|
const scalarQuery = buildScalarQuery(command, parsed.flags);
|
|
7092
8037
|
const fileQuery = loadQueryFromFlags(parsed.flags);
|
|
7093
|
-
|
|
7094
|
-
|
|
8038
|
+
let query = { ...fileQuery ?? {}, ...scalarQuery ?? {} };
|
|
8039
|
+
let body;
|
|
8040
|
+
try {
|
|
8041
|
+
body = loadBodyFromFlags(parsed.flags);
|
|
8042
|
+
} catch (error) {
|
|
8043
|
+
if (error instanceof CLIError && error.code === "INVALID_BODY_JSON" && command.requestType) {
|
|
8044
|
+
throw new CLIError(
|
|
8045
|
+
"INVALID_BODY_JSON",
|
|
8046
|
+
`body json is invalid for ${scope}.${command.commandPath.join(" ")}; retry with retryToolCalls[0] or retryToolCalls[1] when present`,
|
|
8047
|
+
2,
|
|
8048
|
+
buildBodyValidationDetails(scope, command, command.requestType, [{ path: "body", message: "invalid JSON syntax" }], runtimeEnv)
|
|
8049
|
+
);
|
|
8050
|
+
}
|
|
8051
|
+
throw error;
|
|
8052
|
+
}
|
|
7095
8053
|
let validatedBody = body;
|
|
7096
8054
|
if (!command.requestType && body !== void 0) {
|
|
7097
8055
|
throw new CLIError("BODY_JSON_NOT_SUPPORTED", `command does not accept a request body: ${moduleName} ${commandName}`, 2);
|
|
7098
8056
|
}
|
|
7099
8057
|
if (command.requestType) {
|
|
7100
8058
|
if (body === void 0) {
|
|
7101
|
-
throw new CLIError("MISSING_BODY_FILE", `command requires --body-
|
|
8059
|
+
throw new CLIError("MISSING_BODY_FILE", `command requires --body-json or --body-file for ${command.requestType}; prefer --body-json to avoid file creation`, 2);
|
|
8060
|
+
}
|
|
8061
|
+
if (isTableCreateCommand(scope, command)) {
|
|
8062
|
+
requireTableCreateSchemaBody(scope, command, body, runtimeEnv);
|
|
8063
|
+
validateActionSpecificRawBody(scope, command, body, runtimeEnv);
|
|
8064
|
+
const { parent: _parent, ...schemaBody } = isRecord2(body) ? body : {};
|
|
8065
|
+
const parsedBody = getBodySchema("EntitySaveReqVO")?.safeParse(schemaBody);
|
|
8066
|
+
if (!parsedBody?.success) {
|
|
8067
|
+
const message = parsedBody ? parsedBody.error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`).join("; ") : "EntitySaveReqVO schema is not available";
|
|
8068
|
+
throw new CLIError(
|
|
8069
|
+
"BODY_VALIDATION_FAILED",
|
|
8070
|
+
message,
|
|
8071
|
+
2,
|
|
8072
|
+
buildBodyValidationDetails(
|
|
8073
|
+
scope,
|
|
8074
|
+
command,
|
|
8075
|
+
"EntitySaveReqVO",
|
|
8076
|
+
parsedBody && !parsedBody.success ? parsedBody.error.issues.map((issue) => ({
|
|
8077
|
+
path: issue.path.length > 0 ? `body.${issue.path.join(".")}` : "body",
|
|
8078
|
+
message: issue.message
|
|
8079
|
+
})) : [{ path: "body", message }],
|
|
8080
|
+
runtimeEnv
|
|
8081
|
+
)
|
|
8082
|
+
);
|
|
8083
|
+
}
|
|
8084
|
+
return executeTableCreateWithSchema(command, runtimeEnv, parsed.flags, parsedBody.data, fetchImpl);
|
|
7102
8085
|
}
|
|
7103
|
-
validateActionSpecificRawBody(scope, command, body);
|
|
8086
|
+
validateActionSpecificRawBody(scope, command, body, runtimeEnv);
|
|
7104
8087
|
const schema = getBodySchema(command.requestType);
|
|
7105
8088
|
if (schema) {
|
|
7106
8089
|
const parsedBody = schema.safeParse(body);
|
|
@@ -7117,7 +8100,8 @@ async function executeCLI(scope, argv, env, fetchImpl = fetch) {
|
|
|
7117
8100
|
command,
|
|
7118
8101
|
command.requestType,
|
|
7119
8102
|
hasUserScopeIDIssue ? "body.options.user_scope" : "body",
|
|
7120
|
-
hasUserScopeIDIssue ? "access-rule assign-users requires body.options.user_scope[].id to be numeric TenantUser.ID" : message
|
|
8103
|
+
hasUserScopeIDIssue ? "access-rule assign-users requires body.options.user_scope[].id to be numeric TenantUser.ID" : message,
|
|
8104
|
+
runtimeEnv
|
|
7121
8105
|
)
|
|
7122
8106
|
);
|
|
7123
8107
|
}
|
|
@@ -7125,20 +8109,20 @@ async function executeCLI(scope, argv, env, fetchImpl = fetch) {
|
|
|
7125
8109
|
"BODY_VALIDATION_FAILED",
|
|
7126
8110
|
message,
|
|
7127
8111
|
2,
|
|
7128
|
-
|
|
7129
|
-
|
|
7130
|
-
|
|
7131
|
-
|
|
8112
|
+
buildBodyValidationDetails(
|
|
8113
|
+
scope,
|
|
8114
|
+
command,
|
|
8115
|
+
command.requestType,
|
|
8116
|
+
parsedBody.error.issues.map((issue) => ({
|
|
7132
8117
|
path: issue.path.length > 0 ? `body.${issue.path.join(".")}` : "body",
|
|
7133
8118
|
message: issue.message
|
|
7134
8119
|
})),
|
|
7135
|
-
|
|
7136
|
-
|
|
7137
|
-
}
|
|
8120
|
+
runtimeEnv
|
|
8121
|
+
)
|
|
7138
8122
|
);
|
|
7139
8123
|
}
|
|
7140
8124
|
validatedBody = parsedBody.data;
|
|
7141
|
-
validateActionSpecificBody(scope, command, parsed.flags, validatedBody);
|
|
8125
|
+
validateActionSpecificBody(scope, command, parsed.flags, validatedBody, runtimeEnv);
|
|
7142
8126
|
} else {
|
|
7143
8127
|
const unsupportedReason = getUnsupportedBodySchemaReason(command.requestType);
|
|
7144
8128
|
if (unsupportedReason) {
|
|
@@ -7146,23 +8130,27 @@ async function executeCLI(scope, argv, env, fetchImpl = fetch) {
|
|
|
7146
8130
|
operation: `${scope}.${command.module}.${command.functionName}`,
|
|
7147
8131
|
requestType: command.requestType,
|
|
7148
8132
|
reason: unsupportedReason,
|
|
7149
|
-
tsHints: getTypeHints(command.requestType),
|
|
7150
|
-
docHints: getDocHints(command.requestType)
|
|
8133
|
+
tsHints: getTypeHints(command.requestType, runtimeEnv),
|
|
8134
|
+
docHints: getDocHints(command.requestType, runtimeEnv)
|
|
7151
8135
|
});
|
|
7152
8136
|
}
|
|
7153
8137
|
}
|
|
7154
8138
|
}
|
|
8139
|
+
assertNoUserPolicyIDInput(command, runtimeEnv, query, validatedBody);
|
|
7155
8140
|
if (scope === "user" && (command.functionName === "insertEntity" || command.functionName === "updateEntityRow")) {
|
|
7156
8141
|
await validateFileFieldPayloads(scope, command, runtimeEnv, parsed.flags, validatedBody, fetchImpl);
|
|
7157
8142
|
}
|
|
7158
|
-
const
|
|
8143
|
+
const policyInjected = await injectResolvedPolicyID(command, runtimeEnv, parsed.flags, query, validatedBody, fetchImpl);
|
|
8144
|
+
query = policyInjected.query;
|
|
8145
|
+
validatedBody = policyInjected.body;
|
|
8146
|
+
const response = await fetchUpstream(buildURL(runtimeEnv.ARCUBASE_BASE_URL, endpoint, Object.keys(query).length > 0 ? query : void 0), {
|
|
7159
8147
|
method: command.method,
|
|
7160
8148
|
headers: {
|
|
7161
8149
|
...buildRequestHeaders(runtimeEnv),
|
|
7162
8150
|
"Content-Type": "application/json"
|
|
7163
8151
|
},
|
|
7164
8152
|
body: validatedBody === void 0 || command.method === "GET" ? void 0 : JSON.stringify(validatedBody)
|
|
7165
|
-
});
|
|
8153
|
+
}, endpoint, command.method, fetchImpl);
|
|
7166
8154
|
const raw = await response.text();
|
|
7167
8155
|
let parsedResponse = raw;
|
|
7168
8156
|
try {
|
|
@@ -7170,12 +8158,12 @@ async function executeCLI(scope, argv, env, fetchImpl = fetch) {
|
|
|
7170
8158
|
} catch {
|
|
7171
8159
|
}
|
|
7172
8160
|
if (!response.ok) {
|
|
7173
|
-
|
|
8161
|
+
throwUpstreamHTTPError(endpoint, command.method, response, parsedResponse);
|
|
7174
8162
|
}
|
|
7175
8163
|
if (parsedResponse && typeof parsedResponse === "object" && "error" in parsedResponse && parsedResponse.error) {
|
|
7176
8164
|
const upstreamError = parsedResponse.error;
|
|
7177
|
-
const upstreamMessage =
|
|
7178
|
-
const traceId =
|
|
8165
|
+
const upstreamMessage = upstreamErrorMessage(upstreamError);
|
|
8166
|
+
const traceId = extractTraceID(parsedResponse);
|
|
7179
8167
|
const uploadBindFailure = upstreamMessage.includes("failed to bind upload to assets");
|
|
7180
8168
|
throw new CLIError("UPSTREAM_BODY_ERROR", upstreamMessage, 1, {
|
|
7181
8169
|
endpoint,
|
|
@@ -7184,19 +8172,21 @@ async function executeCLI(scope, argv, env, fetchImpl = fetch) {
|
|
|
7184
8172
|
upstreamError,
|
|
7185
8173
|
...uploadBindFailure ? {
|
|
7186
8174
|
reason: "the row payload used a file/image upload entry, but Arcubase could not bind that upload into an asset record",
|
|
7187
|
-
hint: "verify the upload storage host is reachable from the Arcubase server, then
|
|
8175
|
+
hint: "verify the upload storage host is reachable from the Arcubase server, then use the upload token flow again and retry the row insert/update",
|
|
7188
8176
|
docHints: [
|
|
7189
|
-
{ title: "Uploads", file: "
|
|
7190
|
-
{ title: "Row CRUD", file: "
|
|
8177
|
+
{ title: "Uploads", file: "docs/runtime-reference/uploads.md" },
|
|
8178
|
+
{ title: "Row CRUD", file: "docs/runtime-reference/row-crud.md" }
|
|
7191
8179
|
]
|
|
7192
8180
|
} : {}
|
|
7193
8181
|
});
|
|
7194
8182
|
}
|
|
8183
|
+
const rowValueEvidence = buildRowValueEvidence(command, parsedResponse);
|
|
7195
8184
|
return {
|
|
7196
8185
|
kind: "result",
|
|
7197
8186
|
commandPath: command.commandPath,
|
|
7198
8187
|
status: response.status,
|
|
7199
|
-
data: parsedResponse
|
|
8188
|
+
data: parsedResponse,
|
|
8189
|
+
...rowValueEvidence ? { rowValueEvidence } : {}
|
|
7200
8190
|
};
|
|
7201
8191
|
}
|
|
7202
8192
|
|