@carthooks/arcubase-cli 0.1.19 → 0.1.21

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.
Files changed (44) hide show
  1. package/bundle/arcubase-admin.mjs +727 -45
  2. package/bundle/arcubase.mjs +727 -45
  3. package/dist/generated/command_registry.generated.d.ts +15 -0
  4. package/dist/generated/command_registry.generated.d.ts.map +1 -1
  5. package/dist/generated/command_registry.generated.js +21 -0
  6. package/dist/generated/help_examples.generated.d.ts +319 -0
  7. package/dist/generated/help_examples.generated.d.ts.map +1 -0
  8. package/dist/generated/help_examples.generated.js +437 -0
  9. package/dist/generated/type_index.generated.d.ts +4 -0
  10. package/dist/generated/type_index.generated.d.ts.map +1 -1
  11. package/dist/generated/type_index.generated.js +4 -0
  12. package/dist/generated/zod_registry.generated.d.ts +4 -1
  13. package/dist/generated/zod_registry.generated.d.ts.map +1 -1
  14. package/dist/generated/zod_registry.generated.js +4 -0
  15. package/dist/runtime/execute.d.ts.map +1 -1
  16. package/dist/runtime/execute.js +155 -17
  17. package/dist/runtime/help_examples.d.ts +10 -0
  18. package/dist/runtime/help_examples.d.ts.map +1 -0
  19. package/dist/runtime/help_examples.js +48 -0
  20. package/dist/runtime/zod_registry.d.ts.map +1 -1
  21. package/dist/runtime/zod_registry.js +8 -0
  22. package/package.json +4 -3
  23. package/sdk-dist/api/admin/ingress.ts +11 -0
  24. package/sdk-dist/docs/runtime-reference/access-rule.md +19 -0
  25. package/sdk-dist/docs/runtime-reference/help-examples/admin/access-rule/assign-users.json +23 -0
  26. package/sdk-dist/docs/runtime-reference/help-examples/admin/access-rule/bulk-apply.json +105 -0
  27. package/sdk-dist/docs/runtime-reference/help-examples/admin/access-rule/create.json +95 -0
  28. package/sdk-dist/docs/runtime-reference/help-examples/user/row/bulk-update.json +23 -0
  29. package/sdk-dist/docs/runtime-reference/help-examples/user/row/selection-action.json +25 -0
  30. package/sdk-dist/generated/command_registry.generated.ts +21 -0
  31. package/sdk-dist/generated/help_examples.generated.ts +444 -0
  32. package/sdk-dist/generated/type_index.generated.ts +4 -0
  33. package/sdk-dist/generated/zod_registry.generated.ts +6 -0
  34. package/sdk-dist/types/ingress.ts +31 -0
  35. package/src/generated/command_registry.generated.ts +21 -0
  36. package/src/generated/help_examples.generated.ts +444 -0
  37. package/src/generated/type_index.generated.ts +4 -0
  38. package/src/generated/zod_registry.generated.ts +6 -0
  39. package/src/runtime/execute.ts +223 -37
  40. package/src/runtime/help_examples.ts +61 -0
  41. package/src/runtime/zod_registry.ts +8 -0
  42. package/src/tests/command_registry.test.ts +1 -0
  43. package/src/tests/execute_validation.test.ts +113 -0
  44. package/src/tests/help.test.ts +45 -0
@@ -605,6 +605,27 @@ var adminCommands = [
605
605
  "queryParams": [],
606
606
  "responseType": "AppIngressUpdateRespVO"
607
607
  },
608
+ {
609
+ "scope": "admin",
610
+ "module": "access-rule",
611
+ "functionName": "bulkApplyEntityIngress",
612
+ "commandPath": [
613
+ "access-rule",
614
+ "bulk-apply"
615
+ ],
616
+ "method": "POST",
617
+ "endpoint": "/api/apps/:app_id/access-rules/bulk-apply",
618
+ "pathParams": [
619
+ {
620
+ "param": "app_id",
621
+ "flag": "app-id"
622
+ }
623
+ ],
624
+ "controller": "App.IngressBulkApply",
625
+ "requestType": "AppIngressBulkApplyReqVO",
626
+ "queryParams": [],
627
+ "responseType": "AppIngressBulkApplyRespVO"
628
+ },
608
629
  {
609
630
  "scope": "admin",
610
631
  "module": "workflow",
@@ -16092,6 +16113,8 @@ var PermitFieldPermitSchema = external_exports.lazy(() => external_exports.objec
16092
16113
  var PermitPolicySchema = external_exports.lazy(() => external_exports.object({ "actions": external_exports.array(external_exports.string()).optional(), "all_fields_read": external_exports.boolean().optional(), "all_fields_write": external_exports.boolean().optional(), "condition": PermitConditionSetSchema.optional(), "description": external_exports.string().optional(), "fields": external_exports.array(PermitFieldPermitSchema).optional(), "id": external_exports.string().optional(), "key": external_exports.string().optional(), "name": external_exports.string().optional() }).strict());
16093
16114
  var PermitUserScopeSchema = external_exports.lazy(() => external_exports.object({ "data": external_exports.object({ "name": external_exports.string().optional() }).strict().optional(), "id": external_exports.number().optional(), "type": external_exports.string().optional() }).strict());
16094
16115
  var EntityIngressOptionsSchema = external_exports.lazy(() => external_exports.object({ "i18n_name": I18NTextSchema.optional(), "list_options": PermitEntityListOptionsSchema.optional(), "policy": PermitPolicySchema.optional(), "user_scope": external_exports.array(PermitUserScopeSchema).optional() }).strict());
16116
+ var AppIngressBulkApplyItemVOSchema = external_exports.lazy(() => external_exports.object({ "enabled": external_exports.boolean().optional(), "name": external_exports.string().optional(), "options": EntityIngressOptionsSchema.optional(), "rule_id": external_exports.number().optional(), "table_id": external_exports.number().optional(), "type": external_exports.string().optional() }).strict());
16117
+ var AppIngressBulkApplyReqVOSchema = external_exports.lazy(() => external_exports.object({ "dry_run": external_exports.boolean().optional(), "items": external_exports.array(AppIngressBulkApplyItemVOSchema).optional(), "mode": external_exports.string().optional() }).strict());
16095
16118
  var AppIngressCreateReqVOSchema = external_exports.lazy(() => external_exports.object({ "enabled": external_exports.boolean().optional(), "entity_id": external_exports.number().optional(), "icon_name": external_exports.string().optional(), "name": external_exports.string().optional(), "options": EntityIngressOptionsSchema.optional(), "type": external_exports.string().optional(), "url": external_exports.string().optional() }).strict());
16096
16119
  var AppIngressUpdateReqVOSchema = external_exports.lazy(() => external_exports.object({ "enabled": external_exports.boolean().optional(), "name": external_exports.string().optional(), "options": EntityIngressOptionsSchema.optional(), "update": external_exports.array(external_exports.string()).optional() }).strict());
16097
16120
  var GormDeletedAtSchema = external_exports.lazy(() => external_exports.object({ "Time": external_exports.string().optional(), "Valid": external_exports.boolean().optional() }).strict());
@@ -16159,6 +16182,7 @@ var UserProfileUpdateReqVOSchema = external_exports.lazy(() => external_exports.
16159
16182
  var bodySchemas = {
16160
16183
  "AppCreateByTenantsReqVO": AppCreateByTenantsReqVOSchema,
16161
16184
  "AppCreateEntityReqVO": AppCreateEntityReqVOSchema,
16185
+ "AppIngressBulkApplyReqVO": AppIngressBulkApplyReqVOSchema,
16162
16186
  "AppIngressCreateReqVO": AppIngressCreateReqVOSchema,
16163
16187
  "AppIngressUpdateReqVO": AppIngressUpdateReqVOSchema,
16164
16188
  "AppUpdateAppReqVO": AppUpdateAppReqVOSchema,
@@ -16193,6 +16217,10 @@ var typeIndex = {
16193
16217
  "file": "types/app.ts",
16194
16218
  "dependencies": []
16195
16219
  },
16220
+ "AppIngressBulkApplyReqVO": {
16221
+ "file": "types/ingress.ts",
16222
+ "dependencies": []
16223
+ },
16196
16224
  "AppIngressCreateReqVO": {
16197
16225
  "file": "types/ingress.ts",
16198
16226
  "dependencies": []
@@ -17053,6 +17081,10 @@ var docHintIndex = {
17053
17081
  { title: "Access rule", file: "docs/runtime-reference/access-rule.md" },
17054
17082
  examplesIndexDocHint
17055
17083
  ],
17084
+ AppIngressBulkApplyReqVO: [
17085
+ { title: "Access rule", file: "docs/runtime-reference/access-rule.md" },
17086
+ examplesIndexDocHint
17087
+ ],
17056
17088
  EntitySaveReqVO: [
17057
17089
  { title: "Table schema cheatsheet", file: "docs/runtime-reference/entity-schema.md" },
17058
17090
  { title: "Field type index", file: "docs/runtime-reference/entity-schema/README.md" },
@@ -17166,6 +17198,10 @@ var commandDocHintIndex = {
17166
17198
  { title: "Access rule", file: "docs/runtime-reference/access-rule.md" },
17167
17199
  examplesIndexDocHint
17168
17200
  ],
17201
+ "admin.access-rule.bulkApplyEntityIngress": [
17202
+ { title: "Access rule", file: "docs/runtime-reference/access-rule.md" },
17203
+ examplesIndexDocHint
17204
+ ],
17169
17205
  "user.row.insertEntity": [
17170
17206
  { title: "Row CRUD", file: "docs/runtime-reference/row-crud.md" },
17171
17207
  { title: "Uploads", file: "docs/runtime-reference/uploads.md" },
@@ -17416,6 +17452,489 @@ async function uploadLocalFileWithToken(filePath, token, fetchImpl = fetch) {
17416
17452
  return { objectKey };
17417
17453
  }
17418
17454
 
17455
+ // src/generated/help_examples.generated.ts
17456
+ var helpExamplesIndex = {
17457
+ "admin.access-rule.assign-users": {
17458
+ "command": [
17459
+ "access-rule",
17460
+ "assign-users"
17461
+ ],
17462
+ "examples": [
17463
+ {
17464
+ "title": "replace user_scope with user, department, and actor scopes",
17465
+ "body": {
17466
+ "update": [
17467
+ "user_scope"
17468
+ ],
17469
+ "options": {
17470
+ "user_scope": [
17471
+ {
17472
+ "type": "user",
17473
+ "id": 2188889901
17474
+ },
17475
+ {
17476
+ "type": "department",
17477
+ "id": 2188881201
17478
+ },
17479
+ {
17480
+ "type": "actor",
17481
+ "id": 2188883301
17482
+ }
17483
+ ]
17484
+ }
17485
+ },
17486
+ "notes": [
17487
+ "id must be numeric arcubaseUserId, department ID, or actor ID",
17488
+ "assign-users updates user_scope only and preserves the existing policy"
17489
+ ]
17490
+ }
17491
+ ]
17492
+ },
17493
+ "admin.access-rule.bulk-apply": {
17494
+ "command": [
17495
+ "access-rule",
17496
+ "bulk-apply"
17497
+ ],
17498
+ "examples": [
17499
+ {
17500
+ "title": "upsert permission matrix by rule name in one transaction",
17501
+ "body": {
17502
+ "mode": "upsert_by_name",
17503
+ "items": [
17504
+ {
17505
+ "table_id": 2188893443,
17506
+ "name": "Customer archive - sales owns rows",
17507
+ "enabled": true,
17508
+ "type": "form",
17509
+ "options": {
17510
+ "user_scope": [
17511
+ {
17512
+ "type": "department",
17513
+ "id": 2188881201
17514
+ }
17515
+ ],
17516
+ "policy": {
17517
+ "key": "custom",
17518
+ "actions": [
17519
+ "view",
17520
+ "add",
17521
+ "edit"
17522
+ ],
17523
+ "all_fields_read": true,
17524
+ "all_fields_write": true,
17525
+ "condition": {
17526
+ "mode": "and",
17527
+ "conditions": [
17528
+ {
17529
+ "column": "creator",
17530
+ "operator": "$eq",
17531
+ "value": "[[current_user]]",
17532
+ "value_from": 0,
17533
+ "value_relation": ""
17534
+ }
17535
+ ]
17536
+ }
17537
+ },
17538
+ "list_options": {}
17539
+ }
17540
+ },
17541
+ {
17542
+ "table_id": 2188893444,
17543
+ "name": "Lead review - manager queue",
17544
+ "enabled": true,
17545
+ "type": "form",
17546
+ "options": {
17547
+ "user_scope": [
17548
+ {
17549
+ "type": "actor",
17550
+ "id": 2188883301
17551
+ }
17552
+ ],
17553
+ "policy": {
17554
+ "key": "custom",
17555
+ "actions": [
17556
+ "view",
17557
+ "edit"
17558
+ ],
17559
+ "all_fields_read": true,
17560
+ "all_fields_write": true,
17561
+ "condition": {
17562
+ "mode": "and",
17563
+ "conditions": [
17564
+ {
17565
+ "column": ":1004",
17566
+ "operator": "$eq",
17567
+ "value": "pending",
17568
+ "value_from": 0,
17569
+ "value_relation": ""
17570
+ },
17571
+ {
17572
+ "column": "",
17573
+ "operator": "",
17574
+ "value": null,
17575
+ "value_from": 0,
17576
+ "value_relation": "",
17577
+ "subset": {
17578
+ "mode": "or",
17579
+ "conditions": [
17580
+ {
17581
+ "column": "creator",
17582
+ "operator": "$eq",
17583
+ "value": "[[current_user]]",
17584
+ "value_from": 0,
17585
+ "value_relation": ""
17586
+ },
17587
+ {
17588
+ "column": ":1005",
17589
+ "operator": "$eq",
17590
+ "value": "high",
17591
+ "value_from": 0,
17592
+ "value_relation": ""
17593
+ }
17594
+ ]
17595
+ }
17596
+ }
17597
+ ]
17598
+ }
17599
+ },
17600
+ "list_options": {}
17601
+ }
17602
+ }
17603
+ ]
17604
+ },
17605
+ "notes": [
17606
+ "mode upsert_by_name is for idempotent setup; rule names must be unique within each table",
17607
+ "department, actor, and specific user scopes all use options.user_scope",
17608
+ "row-owner isolation uses [[current_user]] in policy.condition"
17609
+ ]
17610
+ },
17611
+ {
17612
+ "title": "preview updates for existing rule ids",
17613
+ "body": {
17614
+ "mode": "update_existing",
17615
+ "dry_run": true,
17616
+ "items": [
17617
+ {
17618
+ "table_id": 2188893443,
17619
+ "rule_id": 2188893557,
17620
+ "enabled": true,
17621
+ "options": {
17622
+ "user_scope": [
17623
+ {
17624
+ "type": "user",
17625
+ "id": 2188889901
17626
+ }
17627
+ ],
17628
+ "policy": {
17629
+ "key": "custom",
17630
+ "actions": [
17631
+ "view"
17632
+ ],
17633
+ "all_fields_read": true,
17634
+ "all_fields_write": false
17635
+ },
17636
+ "list_options": {}
17637
+ }
17638
+ }
17639
+ ]
17640
+ },
17641
+ "notes": [
17642
+ "dry_run true returns the planned operations without writing",
17643
+ "update_existing requires rule_id on every item"
17644
+ ]
17645
+ }
17646
+ ]
17647
+ },
17648
+ "admin.access-rule.create": {
17649
+ "command": [
17650
+ "access-rule",
17651
+ "create"
17652
+ ],
17653
+ "examples": [
17654
+ {
17655
+ "title": "full access for a specific arcubaseUserId",
17656
+ "body": {
17657
+ "name": "Admin full access",
17658
+ "enabled": true,
17659
+ "type": "form",
17660
+ "options": {
17661
+ "user_scope": [
17662
+ {
17663
+ "type": "user",
17664
+ "id": 2188889977
17665
+ }
17666
+ ],
17667
+ "policy": {
17668
+ "key": "custom",
17669
+ "actions": [
17670
+ "view",
17671
+ "add",
17672
+ "edit",
17673
+ "delete"
17674
+ ],
17675
+ "all_fields_read": true,
17676
+ "all_fields_write": true
17677
+ },
17678
+ "list_options": {}
17679
+ }
17680
+ }
17681
+ },
17682
+ {
17683
+ "title": "department can view/add/edit only rows created by themselves",
17684
+ "body": {
17685
+ "name": "Sales own rows",
17686
+ "enabled": true,
17687
+ "type": "form",
17688
+ "options": {
17689
+ "user_scope": [
17690
+ {
17691
+ "type": "department",
17692
+ "id": 2188881201
17693
+ }
17694
+ ],
17695
+ "policy": {
17696
+ "key": "custom",
17697
+ "actions": [
17698
+ "view",
17699
+ "add",
17700
+ "edit"
17701
+ ],
17702
+ "all_fields_read": true,
17703
+ "all_fields_write": true,
17704
+ "condition": {
17705
+ "mode": "and",
17706
+ "conditions": [
17707
+ {
17708
+ "column": "creator",
17709
+ "operator": "$eq",
17710
+ "value": "[[current_user]]",
17711
+ "value_from": 0,
17712
+ "value_relation": ""
17713
+ }
17714
+ ]
17715
+ }
17716
+ },
17717
+ "list_options": {}
17718
+ }
17719
+ },
17720
+ "notes": [
17721
+ "department scope includes child departments",
17722
+ "row-owner isolation uses [[current_user]] on creator"
17723
+ ]
17724
+ },
17725
+ {
17726
+ "title": "role actor can view rows matching a complex AND/OR condition",
17727
+ "body": {
17728
+ "name": "Sales manager review queue",
17729
+ "enabled": true,
17730
+ "type": "form",
17731
+ "options": {
17732
+ "user_scope": [
17733
+ {
17734
+ "type": "actor",
17735
+ "id": 2188883301
17736
+ }
17737
+ ],
17738
+ "policy": {
17739
+ "key": "custom",
17740
+ "actions": [
17741
+ "view",
17742
+ "edit"
17743
+ ],
17744
+ "all_fields_read": true,
17745
+ "all_fields_write": true,
17746
+ "condition": {
17747
+ "mode": "and",
17748
+ "conditions": [
17749
+ {
17750
+ "column": ":1004",
17751
+ "operator": "$eq",
17752
+ "value": "pending",
17753
+ "value_from": 0,
17754
+ "value_relation": ""
17755
+ },
17756
+ {
17757
+ "column": "",
17758
+ "operator": "",
17759
+ "value": null,
17760
+ "value_from": 0,
17761
+ "value_relation": "",
17762
+ "subset": {
17763
+ "mode": "or",
17764
+ "conditions": [
17765
+ {
17766
+ "column": "creator",
17767
+ "operator": "$eq",
17768
+ "value": "[[current_user]]",
17769
+ "value_from": 0,
17770
+ "value_relation": ""
17771
+ },
17772
+ {
17773
+ "column": ":1005",
17774
+ "operator": "$eq",
17775
+ "value": "high",
17776
+ "value_from": 0,
17777
+ "value_relation": ""
17778
+ }
17779
+ ]
17780
+ }
17781
+ }
17782
+ ]
17783
+ }
17784
+ },
17785
+ "list_options": {}
17786
+ }
17787
+ },
17788
+ "notes": [
17789
+ "actor means Arcubase role id",
17790
+ 'condition mode "and" and "or" are canonical; legacy "all" also reads as AND',
17791
+ "nested OR uses subset and leaves the wrapper column/operator empty"
17792
+ ]
17793
+ }
17794
+ ]
17795
+ },
17796
+ "user.row.bulk-update": {
17797
+ "command": [
17798
+ "row",
17799
+ "bulk-update"
17800
+ ],
17801
+ "examples": [
17802
+ {
17803
+ "title": "bulk update explicit row ids",
17804
+ "body": {
17805
+ "selection": {
17806
+ "type": "ids",
17807
+ "ids": [
17808
+ 2188890411,
17809
+ 2188890412
17810
+ ],
17811
+ "length": 2
17812
+ },
17813
+ "fields": [
17814
+ {
17815
+ "id": 1003,
17816
+ "action": {
17817
+ "type": "set",
17818
+ "value": 2
17819
+ }
17820
+ }
17821
+ ]
17822
+ }
17823
+ },
17824
+ {
17825
+ "title": "bulk update rows selected by a search condition",
17826
+ "body": {
17827
+ "selection": {
17828
+ "type": "condition",
17829
+ "condition": {
17830
+ "selectAll": true,
17831
+ "q": "SO-1001"
17832
+ },
17833
+ "length": 0
17834
+ },
17835
+ "fields": [
17836
+ {
17837
+ "id": 1003,
17838
+ "action": {
17839
+ "type": "set",
17840
+ "value": 2
17841
+ }
17842
+ }
17843
+ ]
17844
+ },
17845
+ "notes": [
17846
+ "condition selection uses row-query style keys such as q, tab, and filter_:1002"
17847
+ ]
17848
+ }
17849
+ ]
17850
+ },
17851
+ "user.row.selection-action": {
17852
+ "command": [
17853
+ "row",
17854
+ "selection-action"
17855
+ ],
17856
+ "examples": [
17857
+ {
17858
+ "title": "run a custom action against explicit row ids",
17859
+ "body": {
17860
+ "selection": {
17861
+ "type": "ids",
17862
+ "ids": [
17863
+ 2188890411
17864
+ ],
17865
+ "length": 1
17866
+ }
17867
+ },
17868
+ "notes": [
17869
+ "pass the backend action code with --action",
17870
+ "for query action, use ids or all selection instead of condition selection"
17871
+ ]
17872
+ },
17873
+ {
17874
+ "title": "run a custom action against a filtered selection",
17875
+ "body": {
17876
+ "selection": {
17877
+ "type": "condition",
17878
+ "condition": {
17879
+ "selectAll": true,
17880
+ "q": "SO-1001"
17881
+ },
17882
+ "length": 0
17883
+ }
17884
+ },
17885
+ "notes": [
17886
+ "condition selection uses row-query style keys such as q, tab, and filter_:1002"
17887
+ ]
17888
+ }
17889
+ ]
17890
+ }
17891
+ };
17892
+
17893
+ // src/runtime/help_examples.ts
17894
+ function binaryForScope(scope) {
17895
+ return scope === "admin" ? "arcubase-admin" : "arcubase";
17896
+ }
17897
+ function getFixedValue(value) {
17898
+ if (!("fixedValue" in value)) {
17899
+ return void 0;
17900
+ }
17901
+ const fixedValue = value.fixedValue;
17902
+ return typeof fixedValue === "string" ? fixedValue : void 0;
17903
+ }
17904
+ function pathFlagPlaceholders(command) {
17905
+ const parts = command.pathParams.filter((item) => !getFixedValue(item)).map((item) => `--${item.flag} <${item.flag.replace(/-/g, "_")}>`);
17906
+ return parts.length > 0 ? `${parts.join(" ")} ` : "";
17907
+ }
17908
+ function helpExampleKey(scope, command) {
17909
+ return `${scope}.${command.commandPath.join(".")}`;
17910
+ }
17911
+ function getCommandHelpExamples(scope, command) {
17912
+ return helpExamplesIndex[helpExampleKey(scope, command)]?.examples ?? [];
17913
+ }
17914
+ function renderCommandHelpExamples(scope, command) {
17915
+ const binary = binaryForScope(scope);
17916
+ const examples = getCommandHelpExamples(scope, command);
17917
+ const header = `${binary} ${command.commandPath.join(" ")} --help-examples`;
17918
+ if (examples.length === 0) {
17919
+ return [
17920
+ header,
17921
+ "",
17922
+ "No dedicated examples for this final command yet.",
17923
+ `Use ${binary} ${command.commandPath.join(" ")} --help for flags, docs, and type paths.`
17924
+ ].join("\n");
17925
+ }
17926
+ return [
17927
+ header,
17928
+ "",
17929
+ ...examples.flatMap((example) => [
17930
+ `${example.title}:`,
17931
+ ...example.body === void 0 ? [] : [` ${binary} ${command.commandPath.join(" ")} ${pathFlagPlaceholders(command)}--body-json '${JSON.stringify(example.body)}'`.replace(/\s+/g, " ").trim()],
17932
+ ...(example.notes ?? []).map((note) => ` - ${note}`),
17933
+ ""
17934
+ ])
17935
+ ].join("\n").trimEnd();
17936
+ }
17937
+
17419
17938
  // src/runtime/execute.ts
17420
17939
  function renderRootHelp(scope) {
17421
17940
  const binary = scope === "admin" ? "arcubase-admin" : "arcubase";
@@ -17453,9 +17972,32 @@ function buildUnknownCommandDetails(scope, moduleName, commandName) {
17453
17972
  const suggestions = findCommandSuggestions(moduleName, commandName).map((item) => `${item.binary} ${item.moduleName}${item.commandName ? ` ${item.commandName}` : ""}`);
17454
17973
  return suggestions.length > 0 ? { suggestions } : void 0;
17455
17974
  }
17975
+ function throwHelpExamplesRequiresCommand(scope, moduleName) {
17976
+ const binary = binaryForScope2(scope);
17977
+ const suggestions = scope === "admin" ? [
17978
+ `${binary} access-rule create --help-examples`,
17979
+ `${binary} access-rule assign-users --help-examples`
17980
+ ] : [
17981
+ `${binary} row bulk-update --help-examples`,
17982
+ `${binary} row selection-action --help-examples`
17983
+ ];
17984
+ throw new CLIError(
17985
+ "HELP_EXAMPLES_REQUIRES_COMMAND",
17986
+ "--help-examples must follow a final command",
17987
+ 2,
17988
+ {
17989
+ operation: moduleName ? `${binary} ${moduleName} --help-examples` : `${binary} --help-examples`,
17990
+ hint: `retry with a final command, for example: ${suggestions[0]}`,
17991
+ suggestions
17992
+ }
17993
+ );
17994
+ }
17456
17995
  function sdkPath2(file2, env = process.env) {
17457
17996
  return resolveArcubaseSDKPath(file2, env);
17458
17997
  }
17998
+ function binaryForScope2(scope) {
17999
+ return scope === "admin" ? "arcubase-admin" : "arcubase";
18000
+ }
17459
18001
  function renderCommandHelp(scope, moduleName, commandName, env = process.env) {
17460
18002
  const command = findCommand(scope, moduleName, commandName);
17461
18003
  if (!command) {
@@ -17466,7 +18008,7 @@ function renderCommandHelp(scope, moduleName, commandName, env = process.env) {
17466
18008
  ...command.requestType ? getDocHints(command.requestType, env) : []
17467
18009
  ].filter((item, index, list) => list.findIndex((candidate) => candidate.file === item.file) === index);
17468
18010
  const typeHints = command.requestType ? getTypeHints(command.requestType, env) : [];
17469
- const pathFlags = command.pathParams.filter((item) => !getFixedValue(item)).map((item) => `--${item.flag}`);
18011
+ const pathFlags = command.pathParams.filter((item) => !getFixedValue2(item)).map((item) => `--${item.flag}`);
17470
18012
  const queryFlags = visibleQueryParams(command).map((item) => `--${item.flag}`);
17471
18013
  const isTableCreate = scope === "admin" && command.commandPath[0] === "table" && command.commandPath[1] === "create";
17472
18014
  const bodyTypeText = isTableCreate ? "TableCreateWithSchema" : command.requestType;
@@ -17478,6 +18020,7 @@ function renderCommandHelp(scope, moduleName, commandName, env = process.env) {
17478
18020
  command.requestType ? `body: ${bodyTypeText} via --body-json <json-string> | --body-file <file>.json` : "body: none",
17479
18021
  queryFlags.length ? `query flags: ${queryFlags.join(", ")}, --query-file` : "query flags: --query-file",
17480
18022
  pathFlags.length ? `path flags: ${pathFlags.join(", ")}` : "path flags: none",
18023
+ `copyable examples: ${scope === "admin" ? "arcubase-admin" : "arcubase"} ${command.commandPath.join(" ")} --help-examples`,
17481
18024
  ...isTableCreate ? [
17482
18025
  "body-json example:",
17483
18026
  ` - ${tableCreateExampleBody}`,
@@ -17576,7 +18119,7 @@ function coerceScalar(value, typeText) {
17576
18119
  }
17577
18120
  return value;
17578
18121
  }
17579
- function getFixedValue(value) {
18122
+ function getFixedValue2(value) {
17580
18123
  if (!("fixedValue" in value)) {
17581
18124
  return void 0;
17582
18125
  }
@@ -17586,7 +18129,7 @@ function getFixedValue(value) {
17586
18129
  function resolveEndpoint(command, flags) {
17587
18130
  let resolved = command.endpoint;
17588
18131
  for (const mapping of command.pathParams) {
17589
- const value = getFixedValue(mapping) ?? flagValue(flags, mapping.flag);
18132
+ const value = getFixedValue2(mapping) ?? flagValue(flags, mapping.flag);
17590
18133
  if (!value) {
17591
18134
  throw new CLIError("MISSING_PATH_FLAG", `missing required flag --${mapping.flag}`, 2);
17592
18135
  }
@@ -17600,21 +18143,21 @@ function buildScalarQuery(command, flags) {
17600
18143
  }
17601
18144
  const out = {};
17602
18145
  for (const scalar of effectiveQueryParams(command)) {
17603
- const value = getFixedValue(scalar) ?? flagValue(flags, scalar.flag);
18146
+ const value = getFixedValue2(scalar) ?? flagValue(flags, scalar.flag);
17604
18147
  if (value === void 0) continue;
17605
18148
  out[scalar.key] = coerceScalar(value, scalar.type);
17606
18149
  }
17607
18150
  return Object.keys(out).length > 0 ? out : void 0;
17608
18151
  }
17609
18152
  function validateKnownFlags(command, flags, env = process.env) {
17610
- const allowed = /* @__PURE__ */ new Set(["help", "body-file", "body-json", "query-file"]);
18153
+ const allowed = /* @__PURE__ */ new Set(["help", "help-examples", "body-file", "body-json", "query-file"]);
17611
18154
  for (const mapping of command.pathParams) {
17612
- if (!getFixedValue(mapping)) {
18155
+ if (!getFixedValue2(mapping)) {
17613
18156
  allowed.add(mapping.flag);
17614
18157
  }
17615
18158
  }
17616
18159
  for (const query of visibleQueryParams(command)) {
17617
- if (!getFixedValue(query)) {
18160
+ if (!getFixedValue2(query)) {
17618
18161
  allowed.add(query.flag);
17619
18162
  }
17620
18163
  }
@@ -17652,7 +18195,7 @@ function buildUnknownFlagDetails(command, flag, env = process.env) {
17652
18195
  `do not pass request body fields as --${flag}`,
17653
18196
  "put request body fields inside --body-json <json-string>"
17654
18197
  ];
17655
- 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()];
18198
+ details.suggestions = [`retry with: ${command.commandPath.join(" ")} ${command.pathParams.filter((item) => !getFixedValue2(item)).map((item) => `--${item.flag} <${item.flag.replace(/-/g, "_")}>`).join(" ")} --body-json '<json>'`.replace(/\s+/g, " ").trim()];
17656
18199
  }
17657
18200
  if (command.commandPath[0] === "row" && command.commandPath[1] === "query" && ["limit", "offset", "search", "sorts", "view-mode"].includes(flag)) {
17658
18201
  Object.assign(details, buildBodyGuidance("EntityQueryReqVO"));
@@ -17668,7 +18211,7 @@ function buildUnknownFlagDetails(command, flag, env = process.env) {
17668
18211
  }
17669
18212
  function visibleQueryParams(command) {
17670
18213
  if (!command) return [];
17671
- return effectiveQueryParams(command).filter((item) => !getFixedValue(item));
18214
+ return effectiveQueryParams(command).filter((item) => !getFixedValue2(item));
17672
18215
  }
17673
18216
  function effectiveQueryParams(command) {
17674
18217
  if (!command) return [];
@@ -17917,6 +18460,9 @@ function buildTableCreateExampleBody() {
17917
18460
  function isAssignUsersCommand(scope, command) {
17918
18461
  return scope === "admin" && command.commandPath[0] === "access-rule" && command.commandPath[1] === "assign-users";
17919
18462
  }
18463
+ function isAccessRuleBulkApplyCommand(scope, command) {
18464
+ return scope === "admin" && command.commandPath[0] === "access-rule" && command.commandPath[1] === "bulk-apply";
18465
+ }
17920
18466
  function isTableCreateCommand(scope, command) {
17921
18467
  return scope === "admin" && command.commandPath[0] === "table" && command.commandPath[1] === "create";
17922
18468
  }
@@ -18324,6 +18870,112 @@ function validateAccessRuleUserScope(scope, command, requestType, userScope, env
18324
18870
  }
18325
18871
  }
18326
18872
  }
18873
+ function normalizeNumericAccessRuleUserScopeIDs(scope, command, body) {
18874
+ if (!isAccessRuleCommand(scope, command) || !isRecord3(body)) {
18875
+ return body;
18876
+ }
18877
+ const normalizeUserScope = (userScope) => {
18878
+ if (!Array.isArray(userScope)) return { value: userScope, changed: false };
18879
+ let changed = false;
18880
+ const value = userScope.map((item) => {
18881
+ if (!isRecord3(item) || typeof item.id !== "string" || !/^\d+$/.test(item.id)) {
18882
+ return item;
18883
+ }
18884
+ const id = Number(item.id);
18885
+ if (!Number.isFinite(id) || !Number.isInteger(id)) {
18886
+ return item;
18887
+ }
18888
+ changed = true;
18889
+ return { ...item, id };
18890
+ });
18891
+ return { value, changed };
18892
+ };
18893
+ const normalizeNumericID = (value) => {
18894
+ if (typeof value !== "string" || !/^\d+$/.test(value)) return { value, changed: false };
18895
+ const id = Number(value);
18896
+ if (!Number.isFinite(id) || !Number.isInteger(id)) return { value, changed: false };
18897
+ return { value: id, changed: true };
18898
+ };
18899
+ if (isAccessRuleBulkApplyCommand(scope, command) && Array.isArray(body.items)) {
18900
+ let changed = false;
18901
+ const items = body.items.map((item) => {
18902
+ if (!isRecord3(item)) return item;
18903
+ let nextItem = item;
18904
+ for (const key of ["table_id", "rule_id"]) {
18905
+ const normalized = normalizeNumericID(nextItem[key]);
18906
+ if (normalized.changed) {
18907
+ nextItem = { ...nextItem, [key]: normalized.value };
18908
+ changed = true;
18909
+ }
18910
+ }
18911
+ if (isRecord3(nextItem.options)) {
18912
+ const normalizedUserScope2 = normalizeUserScope(nextItem.options.user_scope);
18913
+ if (normalizedUserScope2.changed) {
18914
+ nextItem = {
18915
+ ...nextItem,
18916
+ options: {
18917
+ ...nextItem.options,
18918
+ user_scope: normalizedUserScope2.value
18919
+ }
18920
+ };
18921
+ changed = true;
18922
+ }
18923
+ }
18924
+ return nextItem;
18925
+ });
18926
+ return changed ? { ...body, items } : body;
18927
+ }
18928
+ if (!isRecord3(body.options)) {
18929
+ return body;
18930
+ }
18931
+ const normalizedUserScope = normalizeUserScope(body.options.user_scope);
18932
+ if (!normalizedUserScope.changed) return body;
18933
+ return {
18934
+ ...body,
18935
+ options: {
18936
+ ...body.options,
18937
+ user_scope: normalizedUserScope.value
18938
+ }
18939
+ };
18940
+ }
18941
+ function validateAccessRulePolicyShape(scope, command, requestType, policy, env, pathPrefix) {
18942
+ const actions = policy && Array.isArray(policy.actions) ? policy.actions : [];
18943
+ if (actions.includes("read") || actions.includes("write")) {
18944
+ throwBodyValidationFailure(
18945
+ '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"',
18946
+ requestType,
18947
+ `${pathPrefix}.actions`,
18948
+ scope,
18949
+ command,
18950
+ env
18951
+ );
18952
+ }
18953
+ const fields = policy && Array.isArray(policy.fields) ? policy.fields : [];
18954
+ const allowedSystemFieldKeys = /* @__PURE__ */ new Set(["created", "updated", "creator"]);
18955
+ for (const [index, field] of fields.entries()) {
18956
+ if (!isRecord3(field)) continue;
18957
+ if (typeof field.key === "number" || typeof field.key === "string" && /^\d+$/.test(field.key)) {
18958
+ throwBodyValidationFailure(
18959
+ 'access-rule policy.fields[].key must be a string prefixed with colon, for example ":1002"; do not use raw numbers',
18960
+ requestType,
18961
+ `${pathPrefix}.fields.${index}.key`,
18962
+ scope,
18963
+ command,
18964
+ env
18965
+ );
18966
+ }
18967
+ if (typeof field.key === "string" && !field.key.startsWith(":") && !allowedSystemFieldKeys.has(field.key)) {
18968
+ throwBodyValidationFailure(
18969
+ 'access-rule policy.fields[].key must use Arcubase permission keys such as ":1002"; do not use FieldVO.key values such as "vote_name"',
18970
+ requestType,
18971
+ `${pathPrefix}.fields.${index}.key`,
18972
+ scope,
18973
+ command,
18974
+ env
18975
+ );
18976
+ }
18977
+ }
18978
+ }
18327
18979
  function requireUpdateContains(scope, command, body, field, env) {
18328
18980
  if (!(field in body)) return;
18329
18981
  const update = stringArray(body.update);
@@ -18369,6 +19021,54 @@ function validateActionSpecificRawBody(scope, command, body, env) {
18369
19021
  }
18370
19022
  }
18371
19023
  if (isAccessRuleCommand(scope, command)) {
19024
+ if (isAccessRuleBulkApplyCommand(scope, command)) {
19025
+ if (!Array.isArray(body.items) || body.items.length === 0) {
19026
+ throwBodyValidationFailure(
19027
+ "access-rule bulk-apply requires non-empty body.items; put every table/rule assignment in body.items",
19028
+ command.requestType,
19029
+ "body.items",
19030
+ scope,
19031
+ command,
19032
+ env
19033
+ );
19034
+ }
19035
+ if (body.mode !== void 0 && body.mode !== "update_existing" && body.mode !== "upsert_by_name") {
19036
+ throwBodyValidationFailure(
19037
+ 'access-rule bulk-apply body.mode must be "update_existing" or "upsert_by_name"',
19038
+ command.requestType,
19039
+ "body.mode",
19040
+ scope,
19041
+ command,
19042
+ env
19043
+ );
19044
+ }
19045
+ for (const [index, item] of body.items.entries()) {
19046
+ if (!isRecord3(item)) {
19047
+ throwBodyValidationFailure(
19048
+ "access-rule bulk-apply body.items[] must be an object",
19049
+ command.requestType,
19050
+ `body.items.${index}`,
19051
+ scope,
19052
+ command,
19053
+ env
19054
+ );
19055
+ }
19056
+ const options2 = isRecord3(item.options) ? item.options : void 0;
19057
+ if (!options2) {
19058
+ throwBodyValidationFailure(
19059
+ "access-rule bulk-apply body.items[].options is required and must include the full canonical options object",
19060
+ command.requestType,
19061
+ `body.items.${index}.options`,
19062
+ scope,
19063
+ command,
19064
+ env
19065
+ );
19066
+ }
19067
+ validateAccessRuleUserScope(scope, command, command.requestType, options2.user_scope, env, `body.items.${index}.options.user_scope`);
19068
+ validateAccessRulePolicyShape(scope, command, command.requestType, isRecord3(options2.policy) ? options2.policy : void 0, env, `body.items.${index}.options.policy`);
19069
+ }
19070
+ return;
19071
+ }
18372
19072
  const update = stringArray(body.update);
18373
19073
  if (isAccessRuleUpdateCommand(scope, command) && update.some((item) => item.startsWith("options."))) {
18374
19074
  throwBodyValidationFailure(
@@ -18413,42 +19113,7 @@ function validateActionSpecificRawBody(scope, command, body, env) {
18413
19113
  );
18414
19114
  }
18415
19115
  validateAccessRuleUserScope(scope, command, command.requestType, options?.user_scope, env);
18416
- const actions = policy && Array.isArray(policy.actions) ? policy.actions : [];
18417
- if (actions.includes("read") || actions.includes("write")) {
18418
- throwBodyValidationFailure(
18419
- '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"',
18420
- command.requestType,
18421
- "body.options.policy.actions",
18422
- scope,
18423
- command,
18424
- env
18425
- );
18426
- }
18427
- const fields = policy && Array.isArray(policy.fields) ? policy.fields : [];
18428
- const allowedSystemFieldKeys = /* @__PURE__ */ new Set(["created", "updated", "creator"]);
18429
- for (const [index, field] of fields.entries()) {
18430
- if (!isRecord3(field)) continue;
18431
- if (typeof field.key === "number" || typeof field.key === "string" && /^\d+$/.test(field.key)) {
18432
- throwBodyValidationFailure(
18433
- 'access-rule policy.fields[].key must be a string prefixed with colon, for example ":1002"; do not use raw numbers',
18434
- command.requestType,
18435
- `body.options.policy.fields.${index}.key`,
18436
- scope,
18437
- command,
18438
- env
18439
- );
18440
- }
18441
- if (typeof field.key === "string" && !field.key.startsWith(":") && !allowedSystemFieldKeys.has(field.key)) {
18442
- throwBodyValidationFailure(
18443
- 'access-rule policy.fields[].key must use Arcubase permission keys such as ":1002"; do not use FieldVO.key values such as "vote_name"',
18444
- command.requestType,
18445
- `body.options.policy.fields.${index}.key`,
18446
- scope,
18447
- command,
18448
- env
18449
- );
18450
- }
18451
- }
19116
+ validateAccessRulePolicyShape(scope, command, command.requestType, policy, env, "body.options.policy");
18452
19117
  }
18453
19118
  }
18454
19119
  function validateActionSpecificBody(scope, command, flags, body, env) {
@@ -19124,16 +19789,32 @@ async function executeCLI(scope, argv, env, fetchImpl = fetch) {
19124
19789
  const parsed = parseCLIArgs(argv);
19125
19790
  const envInput = env ?? process.env;
19126
19791
  if (parsed.commandTokens.length === 0) {
19792
+ if (hasFlag(parsed.flags, "help-examples")) {
19793
+ throwHelpExamplesRequiresCommand(scope);
19794
+ }
19127
19795
  return { kind: "help", text: renderRootHelp(scope) };
19128
19796
  }
19129
19797
  const [moduleName, commandName] = parsed.commandTokens;
19130
19798
  if (!moduleName) {
19799
+ if (hasFlag(parsed.flags, "help-examples")) {
19800
+ throwHelpExamplesRequiresCommand(scope);
19801
+ }
19131
19802
  return { kind: "help", text: renderRootHelp(scope) };
19132
19803
  }
19133
19804
  const singleTokenCommand = !commandName ? findCommand(scope, moduleName) : null;
19134
19805
  if (!commandName && !singleTokenCommand) {
19806
+ if (hasFlag(parsed.flags, "help-examples")) {
19807
+ throwHelpExamplesRequiresCommand(scope, moduleName);
19808
+ }
19135
19809
  return { kind: "help", text: renderModuleHelp(scope, moduleName, envInput) };
19136
19810
  }
19811
+ if (hasFlag(parsed.flags, "help-examples")) {
19812
+ const command2 = commandName ? findCommand(scope, moduleName, commandName) : singleTokenCommand;
19813
+ if (!command2) {
19814
+ throw new CLIError("UNKNOWN_COMMAND", `unknown command: ${moduleName}${commandName ? ` ${commandName}` : ""}`, 2, buildUnknownCommandDetails(scope, moduleName, commandName ?? ""));
19815
+ }
19816
+ return { kind: "help", text: renderCommandHelpExamples(scope, command2) };
19817
+ }
19137
19818
  if (hasFlag(parsed.flags, "help")) {
19138
19819
  return { kind: "help", text: renderCommandHelp(scope, moduleName, commandName, envInput) };
19139
19820
  }
@@ -19178,6 +19859,7 @@ async function executeCLI(scope, argv, env, fetchImpl = fetch) {
19178
19859
  if (body === void 0) {
19179
19860
  throw new CLIError("MISSING_BODY_FILE", `command requires --body-json or --body-file for ${command.requestType}; prefer --body-json to avoid file creation`, 2);
19180
19861
  }
19862
+ body = normalizeNumericAccessRuleUserScopeIDs(scope, command, body);
19181
19863
  if (isTableCreateCommand(scope, command)) {
19182
19864
  requireTableCreateSchemaBody(scope, command, body, runtimeEnv);
19183
19865
  validateActionSpecificRawBody(scope, command, body, runtimeEnv);