@carthooks/arcubase-cli 0.1.18 → 0.1.20

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 (31) hide show
  1. package/bundle/arcubase-admin.mjs +423 -34
  2. package/bundle/arcubase.mjs +423 -34
  3. package/dist/generated/help_examples.generated.d.ts +205 -0
  4. package/dist/generated/help_examples.generated.d.ts.map +1 -0
  5. package/dist/generated/help_examples.generated.js +282 -0
  6. package/dist/generated/zod_registry.generated.d.ts.map +1 -1
  7. package/dist/generated/zod_registry.generated.js +1 -1
  8. package/dist/runtime/execute.d.ts.map +1 -1
  9. package/dist/runtime/execute.js +84 -17
  10. package/dist/runtime/help_examples.d.ts +10 -0
  11. package/dist/runtime/help_examples.d.ts.map +1 -0
  12. package/dist/runtime/help_examples.js +48 -0
  13. package/package.json +4 -3
  14. package/sdk-dist/docs/runtime-reference/access-rule.md +12 -10
  15. package/sdk-dist/docs/runtime-reference/help-examples/admin/access-rule/assign-users.json +23 -0
  16. package/sdk-dist/docs/runtime-reference/help-examples/admin/access-rule/create.json +95 -0
  17. package/sdk-dist/docs/runtime-reference/help-examples/user/row/bulk-update.json +23 -0
  18. package/sdk-dist/docs/runtime-reference/help-examples/user/row/selection-action.json +25 -0
  19. package/sdk-dist/generated/help_examples.generated.ts +289 -0
  20. package/sdk-dist/generated/zod_registry.generated.ts +1 -1
  21. package/sdk-dist/types/common.ts +1 -0
  22. package/sdk-dist/types/entity.ts +1 -1
  23. package/sdk-dist/types/kiosk-ui.ts +1 -1
  24. package/sdk-dist/types/tenant.ts +1 -1
  25. package/src/generated/help_examples.generated.ts +289 -0
  26. package/src/generated/zod_registry.generated.ts +1 -1
  27. package/src/runtime/execute.ts +98 -25
  28. package/src/runtime/help_examples.ts +61 -0
  29. package/src/tests/execute_validation.test.ts +88 -10
  30. package/src/tests/help.test.ts +35 -1
  31. package/src/tests/zod_registry.test.ts +38 -0
@@ -16081,7 +16081,7 @@ var AppCreateEntityReqVOSchema = external_exports.lazy(() => external_exports.ob
16081
16081
  var I18NTextSchema = external_exports.lazy(() => external_exports.record(external_exports.string(), external_exports.string()));
16082
16082
  var PermitColumnSchema = external_exports.lazy(() => external_exports.object({ "field_id": external_exports.number().optional(), "is_field": external_exports.boolean().optional(), "prop": external_exports.string().optional() }).strict());
16083
16083
  var PermitSearchColumnSchema = external_exports.lazy(() => external_exports.object({ "default": external_exports.boolean().optional(), "default_value": external_exports.array(external_exports.number()).optional(), "field_id": external_exports.number().optional(), "infilter": external_exports.boolean().optional(), "is_field": external_exports.boolean().optional(), "pinned": external_exports.boolean().optional(), "prop": external_exports.string().optional(), "wildcard": external_exports.boolean().optional() }).strict());
16084
- var PermitEntityPropSchema = external_exports.lazy(() => external_exports.union([external_exports.literal("created"), external_exports.literal("updated"), external_exports.literal("creator")]));
16084
+ var PermitEntityPropSchema = external_exports.lazy(() => external_exports.string().min(1));
16085
16085
  var PermitValueFromSchema = external_exports.lazy(() => external_exports.union([external_exports.literal(1), external_exports.literal(2), external_exports.literal(3)]));
16086
16086
  var PermitRecordConditionSchema = external_exports.lazy(() => external_exports.object({ "column": PermitEntityPropSchema.optional(), "operator": external_exports.string().optional(), "subset": PermitConditionSetSchema.optional(), "value": external_exports.any().optional(), "value_from": PermitValueFromSchema.optional(), "value_relation": PermitEntityPropSchema.optional() }).strict());
16087
16087
  var PermitConditionSetSchema = external_exports.lazy(() => external_exports.object({ "conditions": external_exports.array(PermitRecordConditionSchema).optional(), "mode": external_exports.string().optional() }).strict());
@@ -17416,6 +17416,334 @@ async function uploadLocalFileWithToken(filePath, token, fetchImpl = fetch) {
17416
17416
  return { objectKey };
17417
17417
  }
17418
17418
 
17419
+ // src/generated/help_examples.generated.ts
17420
+ var helpExamplesIndex = {
17421
+ "admin.access-rule.assign-users": {
17422
+ "command": [
17423
+ "access-rule",
17424
+ "assign-users"
17425
+ ],
17426
+ "examples": [
17427
+ {
17428
+ "title": "replace user_scope with user, department, and actor scopes",
17429
+ "body": {
17430
+ "update": [
17431
+ "user_scope"
17432
+ ],
17433
+ "options": {
17434
+ "user_scope": [
17435
+ {
17436
+ "type": "user",
17437
+ "id": 2188889901
17438
+ },
17439
+ {
17440
+ "type": "department",
17441
+ "id": 2188881201
17442
+ },
17443
+ {
17444
+ "type": "actor",
17445
+ "id": 2188883301
17446
+ }
17447
+ ]
17448
+ }
17449
+ },
17450
+ "notes": [
17451
+ "id must be numeric arcubaseUserId, department ID, or actor ID",
17452
+ "assign-users updates user_scope only and preserves the existing policy"
17453
+ ]
17454
+ }
17455
+ ]
17456
+ },
17457
+ "admin.access-rule.create": {
17458
+ "command": [
17459
+ "access-rule",
17460
+ "create"
17461
+ ],
17462
+ "examples": [
17463
+ {
17464
+ "title": "full access for a specific arcubaseUserId",
17465
+ "body": {
17466
+ "name": "Admin full access",
17467
+ "enabled": true,
17468
+ "type": "form",
17469
+ "options": {
17470
+ "user_scope": [
17471
+ {
17472
+ "type": "user",
17473
+ "id": 2188889977
17474
+ }
17475
+ ],
17476
+ "policy": {
17477
+ "key": "custom",
17478
+ "actions": [
17479
+ "view",
17480
+ "add",
17481
+ "edit",
17482
+ "delete"
17483
+ ],
17484
+ "all_fields_read": true,
17485
+ "all_fields_write": true
17486
+ },
17487
+ "list_options": {}
17488
+ }
17489
+ }
17490
+ },
17491
+ {
17492
+ "title": "department can view/add/edit only rows created by themselves",
17493
+ "body": {
17494
+ "name": "Sales own rows",
17495
+ "enabled": true,
17496
+ "type": "form",
17497
+ "options": {
17498
+ "user_scope": [
17499
+ {
17500
+ "type": "department",
17501
+ "id": 2188881201
17502
+ }
17503
+ ],
17504
+ "policy": {
17505
+ "key": "custom",
17506
+ "actions": [
17507
+ "view",
17508
+ "add",
17509
+ "edit"
17510
+ ],
17511
+ "all_fields_read": true,
17512
+ "all_fields_write": true,
17513
+ "condition": {
17514
+ "mode": "and",
17515
+ "conditions": [
17516
+ {
17517
+ "column": "creator",
17518
+ "operator": "$eq",
17519
+ "value": "[[current_user]]",
17520
+ "value_from": 0,
17521
+ "value_relation": ""
17522
+ }
17523
+ ]
17524
+ }
17525
+ },
17526
+ "list_options": {}
17527
+ }
17528
+ },
17529
+ "notes": [
17530
+ "department scope includes child departments",
17531
+ "row-owner isolation uses [[current_user]] on creator"
17532
+ ]
17533
+ },
17534
+ {
17535
+ "title": "role actor can view rows matching a complex AND/OR condition",
17536
+ "body": {
17537
+ "name": "Sales manager review queue",
17538
+ "enabled": true,
17539
+ "type": "form",
17540
+ "options": {
17541
+ "user_scope": [
17542
+ {
17543
+ "type": "actor",
17544
+ "id": 2188883301
17545
+ }
17546
+ ],
17547
+ "policy": {
17548
+ "key": "custom",
17549
+ "actions": [
17550
+ "view",
17551
+ "edit"
17552
+ ],
17553
+ "all_fields_read": true,
17554
+ "all_fields_write": true,
17555
+ "condition": {
17556
+ "mode": "and",
17557
+ "conditions": [
17558
+ {
17559
+ "column": ":1004",
17560
+ "operator": "$eq",
17561
+ "value": "pending",
17562
+ "value_from": 0,
17563
+ "value_relation": ""
17564
+ },
17565
+ {
17566
+ "column": "",
17567
+ "operator": "",
17568
+ "value": null,
17569
+ "value_from": 0,
17570
+ "value_relation": "",
17571
+ "subset": {
17572
+ "mode": "or",
17573
+ "conditions": [
17574
+ {
17575
+ "column": "creator",
17576
+ "operator": "$eq",
17577
+ "value": "[[current_user]]",
17578
+ "value_from": 0,
17579
+ "value_relation": ""
17580
+ },
17581
+ {
17582
+ "column": ":1005",
17583
+ "operator": "$eq",
17584
+ "value": "high",
17585
+ "value_from": 0,
17586
+ "value_relation": ""
17587
+ }
17588
+ ]
17589
+ }
17590
+ }
17591
+ ]
17592
+ }
17593
+ },
17594
+ "list_options": {}
17595
+ }
17596
+ },
17597
+ "notes": [
17598
+ "actor means Arcubase role id",
17599
+ 'condition mode "and" and "or" are canonical; legacy "all" also reads as AND',
17600
+ "nested OR uses subset and leaves the wrapper column/operator empty"
17601
+ ]
17602
+ }
17603
+ ]
17604
+ },
17605
+ "user.row.bulk-update": {
17606
+ "command": [
17607
+ "row",
17608
+ "bulk-update"
17609
+ ],
17610
+ "examples": [
17611
+ {
17612
+ "title": "bulk update explicit row ids",
17613
+ "body": {
17614
+ "selection": {
17615
+ "type": "ids",
17616
+ "ids": [
17617
+ 2188890411,
17618
+ 2188890412
17619
+ ],
17620
+ "length": 2
17621
+ },
17622
+ "fields": [
17623
+ {
17624
+ "id": 1003,
17625
+ "action": {
17626
+ "type": "set",
17627
+ "value": 2
17628
+ }
17629
+ }
17630
+ ]
17631
+ }
17632
+ },
17633
+ {
17634
+ "title": "bulk update rows selected by a search condition",
17635
+ "body": {
17636
+ "selection": {
17637
+ "type": "condition",
17638
+ "condition": {
17639
+ "selectAll": true,
17640
+ "q": "SO-1001"
17641
+ },
17642
+ "length": 0
17643
+ },
17644
+ "fields": [
17645
+ {
17646
+ "id": 1003,
17647
+ "action": {
17648
+ "type": "set",
17649
+ "value": 2
17650
+ }
17651
+ }
17652
+ ]
17653
+ },
17654
+ "notes": [
17655
+ "condition selection uses row-query style keys such as q, tab, and filter_:1002"
17656
+ ]
17657
+ }
17658
+ ]
17659
+ },
17660
+ "user.row.selection-action": {
17661
+ "command": [
17662
+ "row",
17663
+ "selection-action"
17664
+ ],
17665
+ "examples": [
17666
+ {
17667
+ "title": "run a custom action against explicit row ids",
17668
+ "body": {
17669
+ "selection": {
17670
+ "type": "ids",
17671
+ "ids": [
17672
+ 2188890411
17673
+ ],
17674
+ "length": 1
17675
+ }
17676
+ },
17677
+ "notes": [
17678
+ "pass the backend action code with --action",
17679
+ "for query action, use ids or all selection instead of condition selection"
17680
+ ]
17681
+ },
17682
+ {
17683
+ "title": "run a custom action against a filtered selection",
17684
+ "body": {
17685
+ "selection": {
17686
+ "type": "condition",
17687
+ "condition": {
17688
+ "selectAll": true,
17689
+ "q": "SO-1001"
17690
+ },
17691
+ "length": 0
17692
+ }
17693
+ },
17694
+ "notes": [
17695
+ "condition selection uses row-query style keys such as q, tab, and filter_:1002"
17696
+ ]
17697
+ }
17698
+ ]
17699
+ }
17700
+ };
17701
+
17702
+ // src/runtime/help_examples.ts
17703
+ function binaryForScope(scope) {
17704
+ return scope === "admin" ? "arcubase-admin" : "arcubase";
17705
+ }
17706
+ function getFixedValue(value) {
17707
+ if (!("fixedValue" in value)) {
17708
+ return void 0;
17709
+ }
17710
+ const fixedValue = value.fixedValue;
17711
+ return typeof fixedValue === "string" ? fixedValue : void 0;
17712
+ }
17713
+ function pathFlagPlaceholders(command) {
17714
+ const parts = command.pathParams.filter((item) => !getFixedValue(item)).map((item) => `--${item.flag} <${item.flag.replace(/-/g, "_")}>`);
17715
+ return parts.length > 0 ? `${parts.join(" ")} ` : "";
17716
+ }
17717
+ function helpExampleKey(scope, command) {
17718
+ return `${scope}.${command.commandPath.join(".")}`;
17719
+ }
17720
+ function getCommandHelpExamples(scope, command) {
17721
+ return helpExamplesIndex[helpExampleKey(scope, command)]?.examples ?? [];
17722
+ }
17723
+ function renderCommandHelpExamples(scope, command) {
17724
+ const binary = binaryForScope(scope);
17725
+ const examples = getCommandHelpExamples(scope, command);
17726
+ const header = `${binary} ${command.commandPath.join(" ")} --help-examples`;
17727
+ if (examples.length === 0) {
17728
+ return [
17729
+ header,
17730
+ "",
17731
+ "No dedicated examples for this final command yet.",
17732
+ `Use ${binary} ${command.commandPath.join(" ")} --help for flags, docs, and type paths.`
17733
+ ].join("\n");
17734
+ }
17735
+ return [
17736
+ header,
17737
+ "",
17738
+ ...examples.flatMap((example) => [
17739
+ `${example.title}:`,
17740
+ ...example.body === void 0 ? [] : [` ${binary} ${command.commandPath.join(" ")} ${pathFlagPlaceholders(command)}--body-json '${JSON.stringify(example.body)}'`.replace(/\s+/g, " ").trim()],
17741
+ ...(example.notes ?? []).map((note) => ` - ${note}`),
17742
+ ""
17743
+ ])
17744
+ ].join("\n").trimEnd();
17745
+ }
17746
+
17419
17747
  // src/runtime/execute.ts
17420
17748
  function renderRootHelp(scope) {
17421
17749
  const binary = scope === "admin" ? "arcubase-admin" : "arcubase";
@@ -17453,9 +17781,32 @@ function buildUnknownCommandDetails(scope, moduleName, commandName) {
17453
17781
  const suggestions = findCommandSuggestions(moduleName, commandName).map((item) => `${item.binary} ${item.moduleName}${item.commandName ? ` ${item.commandName}` : ""}`);
17454
17782
  return suggestions.length > 0 ? { suggestions } : void 0;
17455
17783
  }
17784
+ function throwHelpExamplesRequiresCommand(scope, moduleName) {
17785
+ const binary = binaryForScope2(scope);
17786
+ const suggestions = scope === "admin" ? [
17787
+ `${binary} access-rule create --help-examples`,
17788
+ `${binary} access-rule assign-users --help-examples`
17789
+ ] : [
17790
+ `${binary} row bulk-update --help-examples`,
17791
+ `${binary} row selection-action --help-examples`
17792
+ ];
17793
+ throw new CLIError(
17794
+ "HELP_EXAMPLES_REQUIRES_COMMAND",
17795
+ "--help-examples must follow a final command",
17796
+ 2,
17797
+ {
17798
+ operation: moduleName ? `${binary} ${moduleName} --help-examples` : `${binary} --help-examples`,
17799
+ hint: `retry with a final command, for example: ${suggestions[0]}`,
17800
+ suggestions
17801
+ }
17802
+ );
17803
+ }
17456
17804
  function sdkPath2(file2, env = process.env) {
17457
17805
  return resolveArcubaseSDKPath(file2, env);
17458
17806
  }
17807
+ function binaryForScope2(scope) {
17808
+ return scope === "admin" ? "arcubase-admin" : "arcubase";
17809
+ }
17459
17810
  function renderCommandHelp(scope, moduleName, commandName, env = process.env) {
17460
17811
  const command = findCommand(scope, moduleName, commandName);
17461
17812
  if (!command) {
@@ -17466,7 +17817,7 @@ function renderCommandHelp(scope, moduleName, commandName, env = process.env) {
17466
17817
  ...command.requestType ? getDocHints(command.requestType, env) : []
17467
17818
  ].filter((item, index, list) => list.findIndex((candidate) => candidate.file === item.file) === index);
17468
17819
  const typeHints = command.requestType ? getTypeHints(command.requestType, env) : [];
17469
- const pathFlags = command.pathParams.filter((item) => !getFixedValue(item)).map((item) => `--${item.flag}`);
17820
+ const pathFlags = command.pathParams.filter((item) => !getFixedValue2(item)).map((item) => `--${item.flag}`);
17470
17821
  const queryFlags = visibleQueryParams(command).map((item) => `--${item.flag}`);
17471
17822
  const isTableCreate = scope === "admin" && command.commandPath[0] === "table" && command.commandPath[1] === "create";
17472
17823
  const bodyTypeText = isTableCreate ? "TableCreateWithSchema" : command.requestType;
@@ -17478,6 +17829,7 @@ function renderCommandHelp(scope, moduleName, commandName, env = process.env) {
17478
17829
  command.requestType ? `body: ${bodyTypeText} via --body-json <json-string> | --body-file <file>.json` : "body: none",
17479
17830
  queryFlags.length ? `query flags: ${queryFlags.join(", ")}, --query-file` : "query flags: --query-file",
17480
17831
  pathFlags.length ? `path flags: ${pathFlags.join(", ")}` : "path flags: none",
17832
+ `copyable examples: ${scope === "admin" ? "arcubase-admin" : "arcubase"} ${command.commandPath.join(" ")} --help-examples`,
17481
17833
  ...isTableCreate ? [
17482
17834
  "body-json example:",
17483
17835
  ` - ${tableCreateExampleBody}`,
@@ -17509,17 +17861,17 @@ function renderCommandHelp(scope, moduleName, commandName, env = process.env) {
17509
17861
  ` - hide field: ${JSON.stringify(buildHiddenFieldAccessRuleBody())}`,
17510
17862
  "success requires:",
17511
17863
  " - result.enabled must be true",
17512
- ' - options.user_scope[].type is "user" for tenant users',
17864
+ ' - options.user_scope[].type is "user", "department", or "actor"',
17513
17865
  ' - hidden fields use colon field keys such as ":1002"'
17514
17866
  ] : [],
17515
17867
  ...scope === "admin" && command.commandPath[0] === "access-rule" && command.commandPath[1] === "assign-users" ? [
17516
17868
  "body-json example:",
17517
- ' - {"update":["user_scope"],"options":{"user_scope":[{"type":"user","id":2188889901}]}}',
17869
+ ' - {"update":["user_scope"],"options":{"user_scope":[{"type":"user","id":2188889901},{"type":"department","id":2188881201},{"type":"actor","id":2188883301}]}}',
17518
17870
  "success requires:",
17519
17871
  " - result.enabled must be true",
17520
- " - result.options.user_scope must contain the assigned numeric arcubaseUserId values",
17521
- " - PermitUserScope.id must be the numeric arcubaseUserId",
17522
- " - Do not copy a non-numeric arcubaseUserId into PermitUserScope.id",
17872
+ " - result.options.user_scope must contain every assigned user, department, or actor scope",
17873
+ " - PermitUserScope.id must be the numeric arcubaseUserId, department ID, or actor ID",
17874
+ " - Do not copy a non-numeric BotWorks userId into PermitUserScope.id",
17523
17875
  " - If result.enabled is false, enable the rule first and retry assign-users"
17524
17876
  ] : [],
17525
17877
  ...scope === "admin" && command.commandPath[0] === "app" && command.commandPath[1] === "create-from-bundle-url" ? [
@@ -17576,7 +17928,7 @@ function coerceScalar(value, typeText) {
17576
17928
  }
17577
17929
  return value;
17578
17930
  }
17579
- function getFixedValue(value) {
17931
+ function getFixedValue2(value) {
17580
17932
  if (!("fixedValue" in value)) {
17581
17933
  return void 0;
17582
17934
  }
@@ -17586,7 +17938,7 @@ function getFixedValue(value) {
17586
17938
  function resolveEndpoint(command, flags) {
17587
17939
  let resolved = command.endpoint;
17588
17940
  for (const mapping of command.pathParams) {
17589
- const value = getFixedValue(mapping) ?? flagValue(flags, mapping.flag);
17941
+ const value = getFixedValue2(mapping) ?? flagValue(flags, mapping.flag);
17590
17942
  if (!value) {
17591
17943
  throw new CLIError("MISSING_PATH_FLAG", `missing required flag --${mapping.flag}`, 2);
17592
17944
  }
@@ -17600,21 +17952,21 @@ function buildScalarQuery(command, flags) {
17600
17952
  }
17601
17953
  const out = {};
17602
17954
  for (const scalar of effectiveQueryParams(command)) {
17603
- const value = getFixedValue(scalar) ?? flagValue(flags, scalar.flag);
17955
+ const value = getFixedValue2(scalar) ?? flagValue(flags, scalar.flag);
17604
17956
  if (value === void 0) continue;
17605
17957
  out[scalar.key] = coerceScalar(value, scalar.type);
17606
17958
  }
17607
17959
  return Object.keys(out).length > 0 ? out : void 0;
17608
17960
  }
17609
17961
  function validateKnownFlags(command, flags, env = process.env) {
17610
- const allowed = /* @__PURE__ */ new Set(["help", "body-file", "body-json", "query-file"]);
17962
+ const allowed = /* @__PURE__ */ new Set(["help", "help-examples", "body-file", "body-json", "query-file"]);
17611
17963
  for (const mapping of command.pathParams) {
17612
- if (!getFixedValue(mapping)) {
17964
+ if (!getFixedValue2(mapping)) {
17613
17965
  allowed.add(mapping.flag);
17614
17966
  }
17615
17967
  }
17616
17968
  for (const query of visibleQueryParams(command)) {
17617
- if (!getFixedValue(query)) {
17969
+ if (!getFixedValue2(query)) {
17618
17970
  allowed.add(query.flag);
17619
17971
  }
17620
17972
  }
@@ -17652,7 +18004,7 @@ function buildUnknownFlagDetails(command, flag, env = process.env) {
17652
18004
  `do not pass request body fields as --${flag}`,
17653
18005
  "put request body fields inside --body-json <json-string>"
17654
18006
  ];
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()];
18007
+ 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
18008
  }
17657
18009
  if (command.commandPath[0] === "row" && command.commandPath[1] === "query" && ["limit", "offset", "search", "sorts", "view-mode"].includes(flag)) {
17658
18010
  Object.assign(details, buildBodyGuidance("EntityQueryReqVO"));
@@ -17668,7 +18020,7 @@ function buildUnknownFlagDetails(command, flag, env = process.env) {
17668
18020
  }
17669
18021
  function visibleQueryParams(command) {
17670
18022
  if (!command) return [];
17671
- return effectiveQueryParams(command).filter((item) => !getFixedValue(item));
18023
+ return effectiveQueryParams(command).filter((item) => !getFixedValue2(item));
17672
18024
  }
17673
18025
  function effectiveQueryParams(command) {
17674
18026
  if (!command) return [];
@@ -17990,14 +18342,18 @@ function buildAssignUsersValidationDetails(scope, command, requestType, path3, m
17990
18342
  shapeHint: {
17991
18343
  update: ["user_scope"],
17992
18344
  options: {
17993
- user_scope: [{ type: "user", id: 2188889901 }]
18345
+ user_scope: [
18346
+ { type: "user", id: 2188889901 },
18347
+ { type: "department", id: 2188881201 },
18348
+ { type: "actor", id: 2188883301 }
18349
+ ]
17994
18350
  }
17995
18351
  },
17996
18352
  commonMistakes: [
17997
18353
  "do not use user_scope at top level",
17998
18354
  "do not use users or allowedUsers",
17999
- "do not use non-numeric arcubaseUserId as id",
18000
- "id must be the numeric arcubaseUserId"
18355
+ "do not use non-numeric BotWorks userId as id",
18356
+ "id must be the numeric arcubaseUserId, department ID, or actor ID"
18001
18357
  ]
18002
18358
  };
18003
18359
  }
@@ -18278,7 +18634,7 @@ function validateAccessRuleUserScope(scope, command, requestType, userScope, env
18278
18634
  if (userScope === void 0) return;
18279
18635
  if (!Array.isArray(userScope)) {
18280
18636
  throwBodyValidationFailure(
18281
- 'access-rule user_scope must be an array of {"type":"user","id":2188889901}',
18637
+ 'access-rule user_scope must be an array of {"type":"user","id":2188889901}, {"type":"department","id":2188881201}, or {"type":"actor","id":2188883301}',
18282
18638
  requestType,
18283
18639
  pathPrefix,
18284
18640
  scope,
@@ -18320,6 +18676,31 @@ function validateAccessRuleUserScope(scope, command, requestType, userScope, env
18320
18676
  }
18321
18677
  }
18322
18678
  }
18679
+ function normalizeNumericAccessRuleUserScopeIDs(scope, command, body) {
18680
+ if (!isAccessRuleCommand(scope, command) || !isRecord3(body) || !isRecord3(body.options) || !Array.isArray(body.options.user_scope)) {
18681
+ return body;
18682
+ }
18683
+ let changed = false;
18684
+ const userScope = body.options.user_scope.map((item) => {
18685
+ if (!isRecord3(item) || typeof item.id !== "string" || !/^\d+$/.test(item.id)) {
18686
+ return item;
18687
+ }
18688
+ const id = Number(item.id);
18689
+ if (!Number.isFinite(id) || !Number.isInteger(id)) {
18690
+ return item;
18691
+ }
18692
+ changed = true;
18693
+ return { ...item, id };
18694
+ });
18695
+ if (!changed) return body;
18696
+ return {
18697
+ ...body,
18698
+ options: {
18699
+ ...body.options,
18700
+ user_scope: userScope
18701
+ }
18702
+ };
18703
+ }
18323
18704
  function requireUpdateContains(scope, command, body, field, env) {
18324
18705
  if (!(field in body)) return;
18325
18706
  const update = stringArray(body.update);
@@ -18341,7 +18722,7 @@ function validateActionSpecificRawBody(scope, command, body, env) {
18341
18722
  if (isAssignUsersCommand(scope, command)) {
18342
18723
  if ("users" in body || "allowedUsers" in body || "user_scope" in body) {
18343
18724
  throwBodyValidationFailure(
18344
- 'access-rule assign-users only accepts body.options.user_scope with {"update":["user_scope"],"options":{"user_scope":[{"type":"user","id":2188889901}]}}',
18725
+ 'access-rule assign-users only accepts body.options.user_scope with {"update":["user_scope"],"options":{"user_scope":[{"type":"user","id":2188889901},{"type":"department","id":2188881201},{"type":"actor","id":2188883301}]}}',
18345
18726
  command.requestType,
18346
18727
  "body.options.user_scope",
18347
18728
  scope,
@@ -18462,7 +18843,7 @@ function validateActionSpecificBody(scope, command, flags, body, env) {
18462
18843
  const userScope = options && Array.isArray(options.user_scope) ? options.user_scope : void 0;
18463
18844
  if ("users" in body || "allowedUsers" in body) {
18464
18845
  throwBodyValidationFailure(
18465
- 'access-rule assign-users only accepts body.options.user_scope with {"update":["user_scope"],"options":{"user_scope":[{"type":"user","id":2188889901}]}}',
18846
+ 'access-rule assign-users only accepts body.options.user_scope with {"update":["user_scope"],"options":{"user_scope":[{"type":"user","id":2188889901},{"type":"department","id":2188881201},{"type":"actor","id":2188883301}]}}',
18466
18847
  command.requestType,
18467
18848
  "body.options.user_scope",
18468
18849
  scope,
@@ -18503,19 +18884,9 @@ function validateActionSpecificBody(scope, command, flags, body, env) {
18503
18884
  env
18504
18885
  );
18505
18886
  }
18506
- if (item.type !== "user") {
18507
- throwBodyValidationFailure(
18508
- 'access-rule assign-users requires body.options.user_scope[].type to be "user"',
18509
- command.requestType,
18510
- `body.options.user_scope.${index}.type`,
18511
- scope,
18512
- command,
18513
- env
18514
- );
18515
- }
18516
18887
  if (typeof item.id !== "number" || !Number.isInteger(item.id) || item.id <= 0) {
18517
18888
  throwBodyValidationFailure(
18518
- "access-rule assign-users requires body.options.user_scope[].id to be numeric arcubaseUserId",
18889
+ "access-rule assign-users requires body.options.user_scope[].id to be numeric arcubaseUserId, department ID, or actor ID",
18519
18890
  command.requestType,
18520
18891
  `body.options.user_scope.${index}.id`,
18521
18892
  scope,
@@ -19130,16 +19501,32 @@ async function executeCLI(scope, argv, env, fetchImpl = fetch) {
19130
19501
  const parsed = parseCLIArgs(argv);
19131
19502
  const envInput = env ?? process.env;
19132
19503
  if (parsed.commandTokens.length === 0) {
19504
+ if (hasFlag(parsed.flags, "help-examples")) {
19505
+ throwHelpExamplesRequiresCommand(scope);
19506
+ }
19133
19507
  return { kind: "help", text: renderRootHelp(scope) };
19134
19508
  }
19135
19509
  const [moduleName, commandName] = parsed.commandTokens;
19136
19510
  if (!moduleName) {
19511
+ if (hasFlag(parsed.flags, "help-examples")) {
19512
+ throwHelpExamplesRequiresCommand(scope);
19513
+ }
19137
19514
  return { kind: "help", text: renderRootHelp(scope) };
19138
19515
  }
19139
19516
  const singleTokenCommand = !commandName ? findCommand(scope, moduleName) : null;
19140
19517
  if (!commandName && !singleTokenCommand) {
19518
+ if (hasFlag(parsed.flags, "help-examples")) {
19519
+ throwHelpExamplesRequiresCommand(scope, moduleName);
19520
+ }
19141
19521
  return { kind: "help", text: renderModuleHelp(scope, moduleName, envInput) };
19142
19522
  }
19523
+ if (hasFlag(parsed.flags, "help-examples")) {
19524
+ const command2 = commandName ? findCommand(scope, moduleName, commandName) : singleTokenCommand;
19525
+ if (!command2) {
19526
+ throw new CLIError("UNKNOWN_COMMAND", `unknown command: ${moduleName}${commandName ? ` ${commandName}` : ""}`, 2, buildUnknownCommandDetails(scope, moduleName, commandName ?? ""));
19527
+ }
19528
+ return { kind: "help", text: renderCommandHelpExamples(scope, command2) };
19529
+ }
19143
19530
  if (hasFlag(parsed.flags, "help")) {
19144
19531
  return { kind: "help", text: renderCommandHelp(scope, moduleName, commandName, envInput) };
19145
19532
  }
@@ -19184,6 +19571,7 @@ async function executeCLI(scope, argv, env, fetchImpl = fetch) {
19184
19571
  if (body === void 0) {
19185
19572
  throw new CLIError("MISSING_BODY_FILE", `command requires --body-json or --body-file for ${command.requestType}; prefer --body-json to avoid file creation`, 2);
19186
19573
  }
19574
+ body = normalizeNumericAccessRuleUserScopeIDs(scope, command, body);
19187
19575
  if (isTableCreateCommand(scope, command)) {
19188
19576
  requireTableCreateSchemaBody(scope, command, body, runtimeEnv);
19189
19577
  validateActionSpecificRawBody(scope, command, body, runtimeEnv);
@@ -19217,16 +19605,17 @@ async function executeCLI(scope, argv, env, fetchImpl = fetch) {
19217
19605
  const message = parsedBody.error.issues.map((issue2) => `${issue2.path.join(".")}: ${issue2.message}`).join("; ");
19218
19606
  if (isAssignUsersCommand(scope, command)) {
19219
19607
  const hasUserScopeIDIssue = parsedBody.error.issues.some((issue2) => issue2.path.join(".") === "options.user_scope.0.id" || issue2.path.join(".").startsWith("options.user_scope."));
19608
+ const userScopeIDMessage = "access-rule assign-users requires body.options.user_scope[].id to be numeric arcubaseUserId, department ID, or actor ID";
19220
19609
  throw new CLIError(
19221
19610
  "BODY_VALIDATION_FAILED",
19222
- hasUserScopeIDIssue ? "access-rule assign-users requires body.options.user_scope[].id to be numeric arcubaseUserId" : message,
19611
+ hasUserScopeIDIssue ? userScopeIDMessage : message,
19223
19612
  2,
19224
19613
  buildAssignUsersValidationDetails(
19225
19614
  scope,
19226
19615
  command,
19227
19616
  command.requestType,
19228
19617
  hasUserScopeIDIssue ? "body.options.user_scope" : "body",
19229
- hasUserScopeIDIssue ? "access-rule assign-users requires body.options.user_scope[].id to be numeric arcubaseUserId" : message,
19618
+ hasUserScopeIDIssue ? userScopeIDMessage : message,
19230
19619
  runtimeEnv
19231
19620
  )
19232
19621
  );