@dereekb/dbx-cli 13.11.7 → 13.11.9

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/index.esm.js CHANGED
@@ -9,13 +9,13 @@ import { createInterface } from 'node:readline';
9
9
  import yargs from 'yargs';
10
10
  import { hideBin } from 'yargs/helpers';
11
11
 
12
- function _array_like_to_array$7(arr, len) {
12
+ function _array_like_to_array$8(arr, len) {
13
13
  if (len == null || len > arr.length) len = arr.length;
14
14
  for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
15
15
  return arr2;
16
16
  }
17
- function _array_without_holes$4(arr) {
18
- if (Array.isArray(arr)) return _array_like_to_array$7(arr);
17
+ function _array_without_holes$5(arr) {
18
+ if (Array.isArray(arr)) return _array_like_to_array$8(arr);
19
19
  }
20
20
  function _assert_this_initialized(self) {
21
21
  if (self === void 0) {
@@ -92,10 +92,10 @@ function _instanceof$6(left, right) {
92
92
  function _is_native_function(fn) {
93
93
  return Function.toString.call(fn).indexOf("[native code]") !== -1;
94
94
  }
95
- function _iterable_to_array$4(iter) {
95
+ function _iterable_to_array$5(iter) {
96
96
  if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
97
97
  }
98
- function _non_iterable_spread$4() {
98
+ function _non_iterable_spread$5() {
99
99
  throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
100
100
  }
101
101
  function _object_spread$c(target) {
@@ -126,20 +126,20 @@ function _set_prototype_of(o, p) {
126
126
  };
127
127
  return _set_prototype_of(o, p);
128
128
  }
129
- function _to_consumable_array$4(arr) {
130
- return _array_without_holes$4(arr) || _iterable_to_array$4(arr) || _unsupported_iterable_to_array$7(arr) || _non_iterable_spread$4();
129
+ function _to_consumable_array$5(arr) {
130
+ return _array_without_holes$5(arr) || _iterable_to_array$5(arr) || _unsupported_iterable_to_array$8(arr) || _non_iterable_spread$5();
131
131
  }
132
132
  function _type_of$3(obj) {
133
133
  "@swc/helpers - typeof";
134
134
  return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
135
135
  }
136
- function _unsupported_iterable_to_array$7(o, minLen) {
136
+ function _unsupported_iterable_to_array$8(o, minLen) {
137
137
  if (!o) return;
138
- if (typeof o === "string") return _array_like_to_array$7(o, minLen);
138
+ if (typeof o === "string") return _array_like_to_array$8(o, minLen);
139
139
  var n = Object.prototype.toString.call(o).slice(8, -1);
140
140
  if (n === "Object" && o.constructor) n = o.constructor.name;
141
141
  if (n === "Map" || n === "Set") return Array.from(n);
142
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$7(o, minLen);
142
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$8(o, minLen);
143
143
  }
144
144
  function _wrap_native_super(Class) {
145
145
  var _cache = typeof Map === "function" ? new Map() : undefined;
@@ -188,7 +188,7 @@ function _is_native_reflect_construct() {
188
188
  /id_token[=:]\s*\S+/gi
189
189
  ];
190
190
  var _outputOptions = {};
191
- var _secretPatterns = _to_consumable_array$4(DEFAULT_CLI_SECRET_PATTERNS);
191
+ var _secretPatterns = _to_consumable_array$5(DEFAULT_CLI_SECRET_PATTERNS);
192
192
  var _errorMapper;
193
193
  /**
194
194
  * Configures output options from parsed CLI arguments.
@@ -441,7 +441,7 @@ function pickFromObject(obj, fields) {
441
441
  };
442
442
  }
443
443
 
444
- function asyncGeneratorStep$f(gen, resolve, reject, _next, _throw, key, arg) {
444
+ function asyncGeneratorStep$h(gen, resolve, reject, _next, _throw, key, arg) {
445
445
  try {
446
446
  var info = gen[key](arg);
447
447
  var value = info.value;
@@ -455,16 +455,16 @@ function asyncGeneratorStep$f(gen, resolve, reject, _next, _throw, key, arg) {
455
455
  Promise.resolve(value).then(_next, _throw);
456
456
  }
457
457
  }
458
- function _async_to_generator$f(fn) {
458
+ function _async_to_generator$h(fn) {
459
459
  return function() {
460
460
  var self = this, args = arguments;
461
461
  return new Promise(function(resolve, reject) {
462
462
  var gen = fn.apply(self, args);
463
463
  function _next(value) {
464
- asyncGeneratorStep$f(gen, resolve, reject, _next, _throw, "next", value);
464
+ asyncGeneratorStep$h(gen, resolve, reject, _next, _throw, "next", value);
465
465
  }
466
466
  function _throw(err) {
467
- asyncGeneratorStep$f(gen, resolve, reject, _next, _throw, "throw", err);
467
+ asyncGeneratorStep$h(gen, resolve, reject, _next, _throw, "throw", err);
468
468
  }
469
469
  _next(undefined);
470
470
  });
@@ -474,7 +474,7 @@ function _type_of$2(obj) {
474
474
  "@swc/helpers - typeof";
475
475
  return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
476
476
  }
477
- function _ts_generator$f(thisArg, body) {
477
+ function _ts_generator$h(thisArg, body) {
478
478
  var f, y, t, _ = {
479
479
  label: 0,
480
480
  sent: function() {
@@ -574,6 +574,7 @@ function _ts_generator$f(thisArg, body) {
574
574
  }
575
575
  }
576
576
  var CALL_MODEL_API_PATH = "/model/call";
577
+ var MAX_MODEL_ACCESS_MULTI_READ_KEYS = 50;
577
578
  /**
578
579
  * Posts a typed model call to `<apiBaseUrl>/model/call` with a Bearer access token and parses the JSON response.
579
580
  *
@@ -589,9 +590,9 @@ var CALL_MODEL_API_PATH = "/model/call";
589
590
  * @param input.fetcher - Optional fetch implementation override (used by tests).
590
591
  * @returns The parsed JSON response body cast to `R`.
591
592
  */ function callModelOverHttp(input) {
592
- return _async_to_generator$f(function() {
593
+ return _async_to_generator$h(function() {
593
594
  var _input_fetcher, fetcher, url, res, text, body, _input_params_call, bodyMessage, messageString, message;
594
- return _ts_generator$f(this, function(_state) {
595
+ return _ts_generator$h(this, function(_state) {
595
596
  switch(_state.label){
596
597
  case 0:
597
598
  fetcher = (_input_fetcher = input.fetcher) !== null && _input_fetcher !== void 0 ? _input_fetcher : fetch;
@@ -641,6 +642,163 @@ var CALL_MODEL_API_PATH = "/model/call";
641
642
  });
642
643
  })();
643
644
  }
645
+ /**
646
+ * GETs a single Firestore document by key via the typed model-access endpoint.
647
+ *
648
+ * Calls `<apiBaseUrl>/model/<modelType>/get?key=<encoded key>` with a Bearer access token and
649
+ * returns the parsed `{ key, data }` envelope. Non-2xx responses are mapped to a {@link CliError}
650
+ * with a stable code derived from the status — matching {@link callModelOverHttp}'s error shape.
651
+ *
652
+ * The backend route is implemented by `ModelApiController.getOne` (packages/firebase-server) and
653
+ * enforces `roles: 'read'` via `useModel(...)` so Firestore security rules still apply.
654
+ *
655
+ * @param input - The request envelope describing the API target, access token, model + key, and optional fetch override.
656
+ * @returns The parsed `{ key, data }` envelope.
657
+ */ function getModelOverHttp(input) {
658
+ return _async_to_generator$h(function() {
659
+ var _input_fetcher, fetcher, url, res, _ref, ok, body, fallbackMessage;
660
+ return _ts_generator$h(this, function(_state) {
661
+ switch(_state.label){
662
+ case 0:
663
+ fetcher = (_input_fetcher = input.fetcher) !== null && _input_fetcher !== void 0 ? _input_fetcher : fetch;
664
+ url = "".concat(trimSlash$1(input.apiBaseUrl), "/model/").concat(encodeURIComponent(input.modelType), "/get?key=").concat(encodeURIComponent(input.key));
665
+ return [
666
+ 4,
667
+ fetcher(url, {
668
+ method: 'GET',
669
+ headers: {
670
+ Accept: 'application/json',
671
+ Authorization: "Bearer ".concat(input.accessToken)
672
+ }
673
+ })
674
+ ];
675
+ case 1:
676
+ res = _state.sent();
677
+ return [
678
+ 4,
679
+ readJsonResponse(res)
680
+ ];
681
+ case 2:
682
+ _ref = _state.sent(), ok = _ref.ok, body = _ref.body, fallbackMessage = _ref.fallbackMessage;
683
+ if (!ok) {
684
+ throw new CliError({
685
+ message: "get ".concat(input.modelType, "/").concat(input.key, " failed: ").concat(extractMessage(body, fallbackMessage, res)),
686
+ code: codeForStatus(res.status),
687
+ suggestion: res.status === 401 || res.status === 403 ? 'Run `<cli> auth login` to refresh credentials.' : undefined
688
+ });
689
+ }
690
+ return [
691
+ 2,
692
+ body
693
+ ];
694
+ }
695
+ });
696
+ })();
697
+ }
698
+ /**
699
+ * Batch-reads up to {@link MAX_MODEL_ACCESS_MULTI_READ_KEYS} Firestore documents in a single request.
700
+ *
701
+ * Calls `POST <apiBaseUrl>/model/<modelType>/get` with body `{ keys }` and returns the
702
+ * `{ results, errors }` envelope. The 50-key cap is enforced client-side so the error surfaces
703
+ * with a clear `INVALID_ARGUMENT` code before the request is made.
704
+ *
705
+ * Backend route: `ModelApiController.getMany` (packages/firebase-server). Same `'read'` role enforcement.
706
+ *
707
+ * @param input - The request envelope describing the API target, access token, model, keys, and optional fetch override.
708
+ * @returns The parsed `{ results, errors }` envelope.
709
+ */ function getMultipleModelsOverHttp(input) {
710
+ return _async_to_generator$h(function() {
711
+ var _input_fetcher, fetcher, url, res, _ref, ok, body, fallbackMessage;
712
+ return _ts_generator$h(this, function(_state) {
713
+ switch(_state.label){
714
+ case 0:
715
+ if (input.keys.length === 0) {
716
+ throw new CliError({
717
+ message: 'get-many requires at least one key.',
718
+ code: 'INVALID_ARGUMENT'
719
+ });
720
+ }
721
+ if (input.keys.length > MAX_MODEL_ACCESS_MULTI_READ_KEYS) {
722
+ throw new CliError({
723
+ message: "get-many supports at most ".concat(MAX_MODEL_ACCESS_MULTI_READ_KEYS, " keys (got ").concat(input.keys.length, ")."),
724
+ code: 'INVALID_ARGUMENT'
725
+ });
726
+ }
727
+ fetcher = (_input_fetcher = input.fetcher) !== null && _input_fetcher !== void 0 ? _input_fetcher : fetch;
728
+ url = "".concat(trimSlash$1(input.apiBaseUrl), "/model/").concat(encodeURIComponent(input.modelType), "/get");
729
+ return [
730
+ 4,
731
+ fetcher(url, {
732
+ method: 'POST',
733
+ headers: {
734
+ 'Content-Type': 'application/json',
735
+ Accept: 'application/json',
736
+ Authorization: "Bearer ".concat(input.accessToken)
737
+ },
738
+ body: JSON.stringify({
739
+ keys: input.keys
740
+ })
741
+ })
742
+ ];
743
+ case 1:
744
+ res = _state.sent();
745
+ return [
746
+ 4,
747
+ readJsonResponse(res)
748
+ ];
749
+ case 2:
750
+ _ref = _state.sent(), ok = _ref.ok, body = _ref.body, fallbackMessage = _ref.fallbackMessage;
751
+ if (!ok) {
752
+ throw new CliError({
753
+ message: "get-many ".concat(input.modelType, " failed: ").concat(extractMessage(body, fallbackMessage, res)),
754
+ code: codeForStatus(res.status),
755
+ suggestion: res.status === 401 || res.status === 403 ? 'Run `<cli> auth login` to refresh credentials.' : undefined
756
+ });
757
+ }
758
+ return [
759
+ 2,
760
+ body
761
+ ];
762
+ }
763
+ });
764
+ })();
765
+ }
766
+ function readJsonResponse(res) {
767
+ return _async_to_generator$h(function() {
768
+ var text, body;
769
+ return _ts_generator$h(this, function(_state) {
770
+ switch(_state.label){
771
+ case 0:
772
+ return [
773
+ 4,
774
+ res.text()
775
+ ];
776
+ case 1:
777
+ text = _state.sent();
778
+ if (text.length > 0) {
779
+ try {
780
+ body = JSON.parse(text);
781
+ } catch (unused) {
782
+ body = text;
783
+ }
784
+ }
785
+ return [
786
+ 2,
787
+ {
788
+ ok: res.ok,
789
+ body: body,
790
+ fallbackMessage: text
791
+ }
792
+ ];
793
+ }
794
+ });
795
+ })();
796
+ }
797
+ function extractMessage(body, fallback, res) {
798
+ var bodyMessage = (typeof body === "undefined" ? "undefined" : _type_of$2(body)) === 'object' && body && 'message' in body ? body.message : undefined;
799
+ var messageString = typeof bodyMessage === 'string' ? bodyMessage : undefined;
800
+ return messageString !== null && messageString !== void 0 ? messageString : fallback || "".concat(res.status, " ").concat(res.statusText);
801
+ }
644
802
  function codeForStatus(status) {
645
803
  if (status === 401) return 'AUTH_UNAUTHORIZED';
646
804
  if (status === 403) return 'AUTH_FORBIDDEN';
@@ -708,33 +866,53 @@ var getCliContext = _cliContextSlot.get;
708
866
  /**
709
867
  * Builds a {@link CliContext} for the current invocation.
710
868
  *
711
- * Bundles the env config and access token alongside a `callModel` helper that POSTs to
712
- * `<env.apiBaseUrl>/model/call` with the cached Bearer token.
869
+ * Bundles the env config and access token alongside helpers that POST/GET against
870
+ * `<env.apiBaseUrl>/model/*` with the cached Bearer token.
713
871
  *
714
872
  * @param input - The context inputs.
715
873
  * @param input.cliName - The CLI's binary name.
716
874
  * @param input.envName - The active env name.
717
875
  * @param input.env - The resolved {@link CliEnvConfig} for the active env.
718
876
  * @param input.accessToken - The Bearer access token to include on outgoing API calls.
877
+ * @param input.modelManifest - Optional generated {@link CliModelManifest} for key→modelType resolution.
719
878
  * @returns The constructed {@link CliContext}.
720
879
  * @__NO_SIDE_EFFECTS__
721
880
  */ function createCliContext(input) {
881
+ var apiBaseUrl = input.env.apiBaseUrl;
882
+ var accessToken = input.accessToken;
722
883
  return {
723
884
  cliName: input.cliName,
724
885
  envName: input.envName,
725
886
  env: input.env,
726
- accessToken: input.accessToken,
887
+ accessToken: accessToken,
888
+ modelManifest: input.modelManifest,
727
889
  callModel: function callModel(params) {
728
890
  return callModelOverHttp({
729
- apiBaseUrl: input.env.apiBaseUrl,
730
- accessToken: input.accessToken,
891
+ apiBaseUrl: apiBaseUrl,
892
+ accessToken: accessToken,
731
893
  params: params
732
894
  });
895
+ },
896
+ getModel: function getModel(modelType, key) {
897
+ return getModelOverHttp({
898
+ apiBaseUrl: apiBaseUrl,
899
+ accessToken: accessToken,
900
+ modelType: modelType,
901
+ key: key
902
+ });
903
+ },
904
+ getMultipleModels: function getMultipleModels(modelType, keys) {
905
+ return getMultipleModelsOverHttp({
906
+ apiBaseUrl: apiBaseUrl,
907
+ accessToken: accessToken,
908
+ modelType: modelType,
909
+ keys: keys
910
+ });
733
911
  }
734
912
  };
735
913
  }
736
914
 
737
- function asyncGeneratorStep$e(gen, resolve, reject, _next, _throw, key, arg) {
915
+ function asyncGeneratorStep$g(gen, resolve, reject, _next, _throw, key, arg) {
738
916
  try {
739
917
  var info = gen[key](arg);
740
918
  var value = info.value;
@@ -748,16 +926,16 @@ function asyncGeneratorStep$e(gen, resolve, reject, _next, _throw, key, arg) {
748
926
  Promise.resolve(value).then(_next, _throw);
749
927
  }
750
928
  }
751
- function _async_to_generator$e(fn) {
929
+ function _async_to_generator$g(fn) {
752
930
  return function() {
753
931
  var self = this, args = arguments;
754
932
  return new Promise(function(resolve, reject) {
755
933
  var gen = fn.apply(self, args);
756
934
  function _next(value) {
757
- asyncGeneratorStep$e(gen, resolve, reject, _next, _throw, "next", value);
935
+ asyncGeneratorStep$g(gen, resolve, reject, _next, _throw, "next", value);
758
936
  }
759
937
  function _throw(err) {
760
- asyncGeneratorStep$e(gen, resolve, reject, _next, _throw, "throw", err);
938
+ asyncGeneratorStep$g(gen, resolve, reject, _next, _throw, "throw", err);
761
939
  }
762
940
  _next(undefined);
763
941
  });
@@ -810,7 +988,7 @@ function _object_spread_props$7(target, source) {
810
988
  }
811
989
  return target;
812
990
  }
813
- function _ts_generator$e(thisArg, body) {
991
+ function _ts_generator$g(thisArg, body) {
814
992
  var f, y, t, _ = {
815
993
  label: 0,
816
994
  sent: function() {
@@ -926,9 +1104,9 @@ function _ts_generator$e(thisArg, body) {
926
1104
  return spec.builder ? spec.builder(yargs) : yargs;
927
1105
  },
928
1106
  handler: function handler(argv) {
929
- return _async_to_generator$e(function() {
1107
+ return _async_to_generator$g(function() {
930
1108
  var context, data, params, result, e;
931
- return _ts_generator$e(this, function(_state) {
1109
+ return _ts_generator$g(this, function(_state) {
932
1110
  switch(_state.label){
933
1111
  case 0:
934
1112
  _state.trys.push([
@@ -1089,7 +1267,7 @@ function _ts_generator$e(thisArg, body) {
1089
1267
  });
1090
1268
  }
1091
1269
 
1092
- function asyncGeneratorStep$d(gen, resolve, reject, _next, _throw, key, arg) {
1270
+ function asyncGeneratorStep$f(gen, resolve, reject, _next, _throw, key, arg) {
1093
1271
  try {
1094
1272
  var info = gen[key](arg);
1095
1273
  var value = info.value;
@@ -1103,16 +1281,16 @@ function asyncGeneratorStep$d(gen, resolve, reject, _next, _throw, key, arg) {
1103
1281
  Promise.resolve(value).then(_next, _throw);
1104
1282
  }
1105
1283
  }
1106
- function _async_to_generator$d(fn) {
1284
+ function _async_to_generator$f(fn) {
1107
1285
  return function() {
1108
1286
  var self = this, args = arguments;
1109
1287
  return new Promise(function(resolve, reject) {
1110
1288
  var gen = fn.apply(self, args);
1111
1289
  function _next(value) {
1112
- asyncGeneratorStep$d(gen, resolve, reject, _next, _throw, "next", value);
1290
+ asyncGeneratorStep$f(gen, resolve, reject, _next, _throw, "next", value);
1113
1291
  }
1114
1292
  function _throw(err) {
1115
- asyncGeneratorStep$d(gen, resolve, reject, _next, _throw, "throw", err);
1293
+ asyncGeneratorStep$f(gen, resolve, reject, _next, _throw, "throw", err);
1116
1294
  }
1117
1295
  _next(undefined);
1118
1296
  });
@@ -1173,7 +1351,7 @@ function _object_spread_props$6(target, source) {
1173
1351
  }
1174
1352
  return target;
1175
1353
  }
1176
- function _ts_generator$d(thisArg, body) {
1354
+ function _ts_generator$f(thisArg, body) {
1177
1355
  var f, y, t, _ = {
1178
1356
  label: 0,
1179
1357
  sent: function() {
@@ -1284,9 +1462,9 @@ function _ts_generator$d(thisArg, body) {
1284
1462
  return withCallModelArgs(yargs);
1285
1463
  },
1286
1464
  handler: function handler(argv) {
1287
- return _async_to_generator$d(function() {
1465
+ return _async_to_generator$f(function() {
1288
1466
  var context, data, params, result, e;
1289
- return _ts_generator$d(this, function(_state) {
1467
+ return _ts_generator$f(this, function(_state) {
1290
1468
  switch(_state.label){
1291
1469
  case 0:
1292
1470
  _state.trys.push([
@@ -1344,12 +1522,12 @@ function _ts_generator$d(thisArg, body) {
1344
1522
  }
1345
1523
  };
1346
1524
 
1347
- function _array_like_to_array$6(arr, len) {
1525
+ function _array_like_to_array$7(arr, len) {
1348
1526
  if (len == null || len > arr.length) len = arr.length;
1349
1527
  for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
1350
1528
  return arr2;
1351
1529
  }
1352
- function _array_with_holes$3(arr) {
1530
+ function _array_with_holes$4(arr) {
1353
1531
  if (Array.isArray(arr)) return arr;
1354
1532
  }
1355
1533
  function _instanceof$4(left, right) {
@@ -1360,7 +1538,7 @@ function _instanceof$4(left, right) {
1360
1538
  return left instanceof right;
1361
1539
  }
1362
1540
  }
1363
- function _iterable_to_array_limit$3(arr, i) {
1541
+ function _iterable_to_array_limit$4(arr, i) {
1364
1542
  var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
1365
1543
  if (_i == null) return;
1366
1544
  var _arr = [];
@@ -1384,23 +1562,23 @@ function _iterable_to_array_limit$3(arr, i) {
1384
1562
  }
1385
1563
  return _arr;
1386
1564
  }
1387
- function _non_iterable_rest$3() {
1565
+ function _non_iterable_rest$4() {
1388
1566
  throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
1389
1567
  }
1390
- function _sliced_to_array$3(arr, i) {
1391
- return _array_with_holes$3(arr) || _iterable_to_array_limit$3(arr, i) || _unsupported_iterable_to_array$6(arr, i) || _non_iterable_rest$3();
1568
+ function _sliced_to_array$4(arr, i) {
1569
+ return _array_with_holes$4(arr) || _iterable_to_array_limit$4(arr, i) || _unsupported_iterable_to_array$7(arr, i) || _non_iterable_rest$4();
1392
1570
  }
1393
1571
  function _type_of$1(obj) {
1394
1572
  "@swc/helpers - typeof";
1395
1573
  return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
1396
1574
  }
1397
- function _unsupported_iterable_to_array$6(o, minLen) {
1575
+ function _unsupported_iterable_to_array$7(o, minLen) {
1398
1576
  if (!o) return;
1399
- if (typeof o === "string") return _array_like_to_array$6(o, minLen);
1577
+ if (typeof o === "string") return _array_like_to_array$7(o, minLen);
1400
1578
  var n = Object.prototype.toString.call(o).slice(8, -1);
1401
1579
  if (n === "Object" && o.constructor) n = o.constructor.name;
1402
1580
  if (n === "Map" || n === "Set") return Array.from(n);
1403
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$6(o, minLen);
1581
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$7(o, minLen);
1404
1582
  }
1405
1583
  /**
1406
1584
  * Resolves the manifest entry for `modelType`. Lookup tries
@@ -1431,113 +1609,914 @@ function _unsupported_iterable_to_array$6(o, minLen) {
1431
1609
  _iterator.return();
1432
1610
  }
1433
1611
  } finally{
1434
- if (_didIteratorError) {
1435
- throw _iteratorError;
1436
- }
1612
+ if (_didIteratorError) {
1613
+ throw _iteratorError;
1614
+ }
1615
+ }
1616
+ }
1617
+ return result;
1618
+ }
1619
+ /**
1620
+ * Rewrites the persisted (short) keys in `data` to the long-name form
1621
+ * declared in the model's manifest entry. Recurses into nested object-array
1622
+ * and sub-object fields when the manifest captured a nested field map.
1623
+ *
1624
+ * Returns the input untouched when `modelType` is not in the manifest, when
1625
+ * the model has no fields, or when the input is not a plain object/array.
1626
+ * Unknown keys, primitives, `Date`, `null`, and `undefined` pass through
1627
+ * unchanged.
1628
+ *
1629
+ * @param modelType - the model identifier (`modelType`, `identityConst`,
1630
+ * or `collectionPrefix`) used to look up the rewrite map.
1631
+ * @param data - the value to rewrite (typically a `read`/`query` response
1632
+ * payload).
1633
+ * @param manifest - generated model manifest.
1634
+ * @returns the rewritten value, or `data` unchanged when no rewrite applies.
1635
+ * @__NO_SIDE_EFFECTS__
1636
+ */ function expandModelKeys(modelType, data, manifest) {
1637
+ var entry = findCliModelManifestEntry(modelType, manifest);
1638
+ if (!entry) return data;
1639
+ return rewriteWithFields(data, entry.fields);
1640
+ }
1641
+ function rewriteWithFields(value, fields) {
1642
+ if (Array.isArray(value)) {
1643
+ return value.map(function(item) {
1644
+ return rewriteWithFields(item, fields);
1645
+ });
1646
+ }
1647
+ if (!isPlainObject(value)) return value;
1648
+ var fieldByName = new Map();
1649
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1650
+ try {
1651
+ for(var _iterator = fields[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1652
+ var field = _step.value;
1653
+ fieldByName.set(field.name, field);
1654
+ }
1655
+ } catch (err) {
1656
+ _didIteratorError = true;
1657
+ _iteratorError = err;
1658
+ } finally{
1659
+ try {
1660
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
1661
+ _iterator.return();
1662
+ }
1663
+ } finally{
1664
+ if (_didIteratorError) {
1665
+ throw _iteratorError;
1666
+ }
1667
+ }
1668
+ }
1669
+ var out = {};
1670
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
1671
+ try {
1672
+ for(var _iterator1 = Object.entries(value)[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
1673
+ var _step_value = _sliced_to_array$4(_step1.value, 2), key = _step_value[0], raw = _step_value[1];
1674
+ var field1 = fieldByName.get(key);
1675
+ if (!field1) {
1676
+ out[key] = raw;
1677
+ continue;
1678
+ }
1679
+ var longKey = field1.longName.length > 0 ? field1.longName : key;
1680
+ out[longKey] = rewriteFieldValue(raw, field1);
1681
+ }
1682
+ } catch (err) {
1683
+ _didIteratorError1 = true;
1684
+ _iteratorError1 = err;
1685
+ } finally{
1686
+ try {
1687
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
1688
+ _iterator1.return();
1689
+ }
1690
+ } finally{
1691
+ if (_didIteratorError1) {
1692
+ throw _iteratorError1;
1693
+ }
1694
+ }
1695
+ }
1696
+ return out;
1697
+ }
1698
+ function rewriteFieldValue(value, field) {
1699
+ var nested = field.nestedFields;
1700
+ if (!nested || nested.length === 0) return value;
1701
+ if (field.nestedIsArray) {
1702
+ if (!Array.isArray(value)) return value;
1703
+ return value.map(function(item) {
1704
+ return rewriteWithFields(item, nested);
1705
+ });
1706
+ }
1707
+ if (!isPlainObject(value)) return value;
1708
+ return rewriteWithFields(value, nested);
1709
+ }
1710
+ function isPlainObject(value) {
1711
+ if (value === null || (typeof value === "undefined" ? "undefined" : _type_of$1(value)) !== 'object') return false;
1712
+ if (Array.isArray(value)) return false;
1713
+ if (_instanceof$4(value, Date)) return false;
1714
+ // Objects from JSON.parse have Object.prototype as their proto. Anything
1715
+ // exotic (Map, Set, Buffer, class instances) we leave untouched.
1716
+ var proto = Object.getPrototypeOf(value);
1717
+ return proto === Object.prototype || proto === null;
1718
+ }
1719
+
1720
+ /**
1721
+ * Default command name for the model-decode command. Top-level so it stays
1722
+ * out of the API-call namespace owned by `model <model> <action>`.
1723
+ */ var DEFAULT_MODEL_DECODE_COMMAND_NAME = 'model-decode';
1724
+ /**
1725
+ * Builds the top-level `model-decode <key>` command.
1726
+ *
1727
+ * Splits the supplied Firestore key on `/`, walks `[prefix, id]` pairs, and
1728
+ * resolves each prefix against the manifest. Supports subcollection paths
1729
+ * (`nb/abc/nbn/def` → leaf `Notification` + parent `NotificationBox`).
1730
+ *
1731
+ * Flags:
1732
+ * - `--json` emits a structured `{ ok, data }` envelope instead of the
1733
+ * human-readable block (useful for scripting or LLM agents).
1734
+ *
1735
+ * @param manifest - The generated model manifest (e.g. `DEMO_CLI_MODEL_MANIFEST`).
1736
+ * @param options - Optional overrides; see {@link BuildModelDecodeCommandOptions}.
1737
+ * @returns A yargs `CommandModule` ready to be passed to `runCli({ configCommands })`.
1738
+ * @__NO_SIDE_EFFECTS__
1739
+ */ function buildModelDecodeCommand(manifest, options) {
1740
+ var _ref;
1741
+ var commandName = (_ref = options === null || options === void 0 ? void 0 : options.commandName) !== null && _ref !== void 0 ? _ref : DEFAULT_MODEL_DECODE_COMMAND_NAME;
1742
+ return {
1743
+ command: "".concat(commandName, " <key>"),
1744
+ describe: 'Decode a Firestore model key (e.g. "jwr/abc123") into model + id info using the registered manifest ('.concat(manifest.length, " model").concat(manifest.length === 1 ? '' : 's', ")."),
1745
+ builder: function builder(yargs) {
1746
+ return yargs.positional('key', {
1747
+ type: 'string',
1748
+ describe: 'Firestore model key — prefix/id, supports subcollection paths like `parentPrefix/parentId/childPrefix/childId`.'
1749
+ }).option('json', {
1750
+ type: 'boolean',
1751
+ default: false,
1752
+ describe: 'Emit a structured JSON envelope instead of the human-readable block.'
1753
+ });
1754
+ },
1755
+ handler: function handler(argv) {
1756
+ try {
1757
+ runHandler$1(manifest, argv);
1758
+ } catch (e) {
1759
+ outputError(e);
1760
+ process.exit(1);
1761
+ }
1762
+ }
1763
+ };
1764
+ }
1765
+ function runHandler$1(manifest, argv) {
1766
+ var rawKey = typeof argv.key === 'string' ? argv.key : '';
1767
+ var decoded = decodeFirestoreModelKey(rawKey, manifest);
1768
+ if (argv.json) {
1769
+ outputResult(decoded);
1770
+ return;
1771
+ }
1772
+ process.stdout.write(renderDecodedKey(decoded));
1773
+ }
1774
+ /**
1775
+ * Splits `rawKey` on `/`, resolves each `[prefix, id]` pair against the
1776
+ * manifest, and returns the leaf segment + ancestor chain. Throws
1777
+ * {@link CliError} for malformed inputs.
1778
+ *
1779
+ * @param rawKey - The Firestore key string.
1780
+ * @param manifest - The generated model manifest.
1781
+ * @returns The decoded key with leaf, ancestors, and any unresolved prefixes.
1782
+ * @__NO_SIDE_EFFECTS__
1783
+ */ function decodeFirestoreModelKey(rawKey, manifest) {
1784
+ var trimmed = rawKey.trim();
1785
+ if (trimmed.length === 0) {
1786
+ throw new CliError({
1787
+ message: 'Key is empty. Provide a Firestore key like `sf/abc123`.',
1788
+ code: 'MODEL_DECODE_INVALID_KEY'
1789
+ });
1790
+ }
1791
+ var segments = trimmed.split('/').filter(function(s) {
1792
+ return s.length > 0;
1793
+ });
1794
+ if (segments.length < 2 || segments.length % 2 !== 0) {
1795
+ throw new CliError({
1796
+ message: "Invalid Firestore key '".concat(trimmed, "'. Expected an even number of segments (`prefix/id` pairs). Got ").concat(segments.length, " segment(s)."),
1797
+ code: 'MODEL_DECODE_INVALID_KEY',
1798
+ suggestion: 'Use the format `prefix/id` (or `parentPrefix/parentId/childPrefix/childId` for subcollections).'
1799
+ });
1800
+ }
1801
+ var decoded = [];
1802
+ var unresolved = [];
1803
+ for(var i = 0; i < segments.length; i += 2){
1804
+ var prefix = segments[i];
1805
+ var id = segments[i + 1];
1806
+ var entry = findCliModelManifestEntry(prefix, manifest);
1807
+ if (!entry) {
1808
+ unresolved.push(prefix);
1809
+ }
1810
+ decoded.push(toSegment(prefix, id, entry));
1811
+ }
1812
+ var leaf = decoded[decoded.length - 1];
1813
+ var ancestors = decoded.slice(0, -1);
1814
+ return {
1815
+ key: trimmed,
1816
+ leaf: leaf,
1817
+ ancestors: ancestors,
1818
+ unresolvedPrefixes: unresolved
1819
+ };
1820
+ }
1821
+ function toSegment(prefix, id, entry) {
1822
+ if (!entry) {
1823
+ return {
1824
+ prefix: prefix,
1825
+ id: id
1826
+ };
1827
+ }
1828
+ return {
1829
+ prefix: prefix,
1830
+ id: id,
1831
+ modelName: entry.modelName,
1832
+ modelType: entry.modelType,
1833
+ modelGroup: entry.modelGroup,
1834
+ identityConst: entry.identityConst,
1835
+ parentIdentityConst: entry.parentIdentityConst,
1836
+ sourcePackage: entry.sourcePackage,
1837
+ sourceFile: entry.sourceFile
1838
+ };
1839
+ }
1840
+ /**
1841
+ * Renders a {@link DecodedKey} as a human-readable text block. Mirrors the
1842
+ * MCP `dbx_model_decode` key-mode output for consistency between agent and
1843
+ * shell consumers.
1844
+ *
1845
+ * @param decoded - the decoded key returned by {@link decodeFirestoreModelKey}.
1846
+ * @returns the formatted block with a trailing newline.
1847
+ * @__NO_SIDE_EFFECTS__
1848
+ */ function renderDecodedKey(decoded) {
1849
+ var lines = [];
1850
+ var leaf = decoded.leaf;
1851
+ if (leaf.modelName) {
1852
+ lines.push("Model: ".concat(leaf.modelName));
1853
+ if (leaf.identityConst) lines.push("identityConst: ".concat(leaf.identityConst));
1854
+ if (leaf.modelType) lines.push("modelType: ".concat(leaf.modelType));
1855
+ lines.push("prefix: ".concat(leaf.prefix));
1856
+ lines.push("id: ".concat(leaf.id));
1857
+ if (leaf.modelGroup) lines.push("modelGroup: ".concat(leaf.modelGroup));
1858
+ if (leaf.parentIdentityConst) lines.push("parentIdentityConst: ".concat(leaf.parentIdentityConst));
1859
+ if (leaf.sourcePackage) {
1860
+ var sourceSuffix = leaf.sourceFile ? " (".concat(leaf.sourceFile, ")") : '';
1861
+ lines.push("source: ".concat(leaf.sourcePackage).concat(sourceSuffix));
1862
+ }
1863
+ } else {
1864
+ lines.push("Model: <unknown — prefix '".concat(leaf.prefix, "' not in manifest>"));
1865
+ lines.push("prefix: ".concat(leaf.prefix));
1866
+ lines.push("id: ".concat(leaf.id));
1867
+ }
1868
+ if (decoded.ancestors.length > 0) {
1869
+ lines.push('');
1870
+ lines.push('Parent chain:');
1871
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1872
+ try {
1873
+ for(var _iterator = decoded.ancestors[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1874
+ var ancestor = _step.value;
1875
+ if (ancestor.modelName) {
1876
+ lines.push("- ".concat(ancestor.modelName, " — prefix ").concat(ancestor.prefix, ", id ").concat(ancestor.id));
1877
+ } else {
1878
+ lines.push("- <unknown> — prefix ".concat(ancestor.prefix, ", id ").concat(ancestor.id));
1879
+ }
1880
+ }
1881
+ } catch (err) {
1882
+ _didIteratorError = true;
1883
+ _iteratorError = err;
1884
+ } finally{
1885
+ try {
1886
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
1887
+ _iterator.return();
1888
+ }
1889
+ } finally{
1890
+ if (_didIteratorError) {
1891
+ throw _iteratorError;
1892
+ }
1893
+ }
1894
+ }
1895
+ }
1896
+ if (decoded.unresolvedPrefixes.length > 0) {
1897
+ lines.push('');
1898
+ lines.push("Unresolved prefix".concat(decoded.unresolvedPrefixes.length === 1 ? '' : 'es', ": ").concat(decoded.unresolvedPrefixes.join(', '), ". Run `model-info` to list known models."));
1899
+ }
1900
+ return lines.join('\n') + '\n';
1901
+ }
1902
+
1903
+ function _array_like_to_array$6(arr, len) {
1904
+ if (len == null || len > arr.length) len = arr.length;
1905
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
1906
+ return arr2;
1907
+ }
1908
+ function _array_with_holes$3(arr) {
1909
+ if (Array.isArray(arr)) return arr;
1910
+ }
1911
+ function _array_without_holes$4(arr) {
1912
+ if (Array.isArray(arr)) return _array_like_to_array$6(arr);
1913
+ }
1914
+ function _iterable_to_array$4(iter) {
1915
+ if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
1916
+ }
1917
+ function _iterable_to_array_limit$3(arr, i) {
1918
+ var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
1919
+ if (_i == null) return;
1920
+ var _arr = [];
1921
+ var _n = true;
1922
+ var _d = false;
1923
+ var _s, _e;
1924
+ try {
1925
+ for(_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true){
1926
+ _arr.push(_s.value);
1927
+ if (i && _arr.length === i) break;
1928
+ }
1929
+ } catch (err) {
1930
+ _d = true;
1931
+ _e = err;
1932
+ } finally{
1933
+ try {
1934
+ if (!_n && _i["return"] != null) _i["return"]();
1935
+ } finally{
1936
+ if (_d) throw _e;
1937
+ }
1938
+ }
1939
+ return _arr;
1940
+ }
1941
+ function _non_iterable_rest$3() {
1942
+ throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
1943
+ }
1944
+ function _non_iterable_spread$4() {
1945
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
1946
+ }
1947
+ function _sliced_to_array$3(arr, i) {
1948
+ return _array_with_holes$3(arr) || _iterable_to_array_limit$3(arr, i) || _unsupported_iterable_to_array$6(arr, i) || _non_iterable_rest$3();
1949
+ }
1950
+ function _to_consumable_array$4(arr) {
1951
+ return _array_without_holes$4(arr) || _iterable_to_array$4(arr) || _unsupported_iterable_to_array$6(arr) || _non_iterable_spread$4();
1952
+ }
1953
+ function _unsupported_iterable_to_array$6(o, minLen) {
1954
+ if (!o) return;
1955
+ if (typeof o === "string") return _array_like_to_array$6(o, minLen);
1956
+ var n = Object.prototype.toString.call(o).slice(8, -1);
1957
+ if (n === "Object" && o.constructor) n = o.constructor.name;
1958
+ if (n === "Map" || n === "Set") return Array.from(n);
1959
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$6(o, minLen);
1960
+ }
1961
+ /**
1962
+ * Parses the positionals for the top-level `get <modelOrKey> [key]` command into a
1963
+ * `{ modelType, key }` pair, using the supplied {@link CliModelManifest} to resolve
1964
+ * collection-name prefixes when the explicit-model form is not used.
1965
+ *
1966
+ * Rules:
1967
+ * 1. Two positionals (`modelOrKey` + `key`) — `modelOrKey` is treated as the explicit
1968
+ * `modelType` and `key` is passed through verbatim. No manifest lookup performed.
1969
+ * 2. One positional (`modelOrKey` only) — treated as a full Firestore key (`prefix/id`).
1970
+ * {@link decodeFirestoreModelKey} resolves the prefix against the manifest. Throws
1971
+ * {@link CliError} if the manifest is missing, the prefix is unresolved, or the leaf
1972
+ * has no `modelType`.
1973
+ *
1974
+ * @param input.modelOrKey - The first positional from yargs.
1975
+ * @param input.key - The optional second positional from yargs.
1976
+ * @param input.manifest - The generated model manifest (for prefix lookup).
1977
+ * @returns The parsed `{ modelType, key }` pair.
1978
+ * @__NO_SIDE_EFFECTS__
1979
+ */ function parseGetArgs(input) {
1980
+ var _input_modelOrKey;
1981
+ var _input_key;
1982
+ var modelOrKey = ((_input_modelOrKey = input.modelOrKey) !== null && _input_modelOrKey !== void 0 ? _input_modelOrKey : '').trim();
1983
+ if (modelOrKey.length === 0) {
1984
+ throw new CliError({
1985
+ message: 'get: missing required positional. Usage: `get <key>` or `get <model> <key>`.',
1986
+ code: 'INVALID_ARGUMENT'
1987
+ });
1988
+ }
1989
+ var explicitKey = (_input_key = input.key) === null || _input_key === void 0 ? void 0 : _input_key.trim();
1990
+ if (explicitKey != null && explicitKey.length > 0) {
1991
+ return {
1992
+ modelType: modelOrKey,
1993
+ key: explicitKey
1994
+ };
1995
+ }
1996
+ if (!modelOrKey.includes('/')) {
1997
+ throw new CliError({
1998
+ message: "get: '".concat(modelOrKey, "' looks like a bare doc id. Provide a full key (e.g. 'jws/abc123') or use 'get <model> <key>'."),
1999
+ code: 'INVALID_ARGUMENT'
2000
+ });
2001
+ }
2002
+ var manifest = input.manifest;
2003
+ if (!manifest || manifest.length === 0) {
2004
+ throw new CliError({
2005
+ message: 'get: cannot infer modelType — no model manifest is wired into the CLI. Pass `modelManifest` to `runCli`, or use `get <model> <key>` explicitly.',
2006
+ code: 'INVALID_ARGUMENT'
2007
+ });
2008
+ }
2009
+ var decoded = decodeFirestoreModelKey(modelOrKey, manifest);
2010
+ if (decoded.unresolvedPrefixes.length > 0 || !decoded.leaf.modelType) {
2011
+ throw new CliError({
2012
+ message: "get: unable to resolve modelType for key '".concat(modelOrKey, "'. Unknown prefix: ").concat(decoded.unresolvedPrefixes.join(', ') || decoded.leaf.prefix, ". Known prefixes: ").concat(manifestPrefixList(manifest), "."),
2013
+ code: 'INVALID_ARGUMENT',
2014
+ suggestion: "Run `<cli> model-decode '<key>'` to inspect a key, or use `get <model> <key>` explicitly."
2015
+ });
2016
+ }
2017
+ return {
2018
+ modelType: decoded.leaf.modelType,
2019
+ key: modelOrKey
2020
+ };
2021
+ }
2022
+ /**
2023
+ * Parses the positionals for the top-level `get-many <firstArg> [rest..]` command.
2024
+ *
2025
+ * Rules:
2026
+ * 1. If `firstArg` contains `/` it is treated as a key — all positionals (`firstArg` + `rest`)
2027
+ * are decoded via {@link decodeFirestoreModelKey}. All keys must resolve to the same
2028
+ * `modelType` or a {@link CliError} is thrown (the backend route is single-modelType per call).
2029
+ * 2. Otherwise `firstArg` is treated as the explicit `modelType` and `rest` are the keys.
2030
+ *
2031
+ * Always rejects empty key lists and lists exceeding 50 keys.
2032
+ *
2033
+ * @param input.firstArg - The first positional from yargs.
2034
+ * @param input.rest - The remaining positionals from yargs.
2035
+ * @param input.manifest - The generated model manifest (used only in the inferred-key branch).
2036
+ * @returns The parsed `{ modelType, keys }` pair.
2037
+ * @__NO_SIDE_EFFECTS__
2038
+ */ function parseGetManyArgs(input) {
2039
+ var _input_firstArg, _input_rest;
2040
+ var firstArg = ((_input_firstArg = input.firstArg) !== null && _input_firstArg !== void 0 ? _input_firstArg : '').trim();
2041
+ var rest = ((_input_rest = input.rest) !== null && _input_rest !== void 0 ? _input_rest : []).map(function(s) {
2042
+ return s.trim();
2043
+ }).filter(function(s) {
2044
+ return s.length > 0;
2045
+ });
2046
+ if (firstArg.length === 0) {
2047
+ throw new CliError({
2048
+ message: 'get-many: missing required positionals. Usage: `get-many <key...>` or `get-many <model> <key...>`.',
2049
+ code: 'INVALID_ARGUMENT'
2050
+ });
2051
+ }
2052
+ if (firstArg.includes('/')) {
2053
+ var keys = [
2054
+ firstArg
2055
+ ].concat(_to_consumable_array$4(rest));
2056
+ return inferModelTypeFromKeys(keys, input.manifest);
2057
+ }
2058
+ if (rest.length === 0) {
2059
+ throw new CliError({
2060
+ message: "get-many: '".concat(firstArg, "' has no '/' so it was treated as a model name, but no keys were supplied. Usage: 'get-many <model> <key...>'."),
2061
+ code: 'INVALID_ARGUMENT'
2062
+ });
2063
+ }
2064
+ return {
2065
+ modelType: firstArg,
2066
+ keys: rest
2067
+ };
2068
+ }
2069
+ function inferModelTypeFromKeys(keys, manifest) {
2070
+ if (!manifest || manifest.length === 0) {
2071
+ throw new CliError({
2072
+ message: 'get-many: cannot infer modelType — no model manifest is wired into the CLI. Pass `modelManifest` to `runCli`, or use `get-many <model> <key...>` explicitly.',
2073
+ code: 'INVALID_ARGUMENT'
2074
+ });
2075
+ }
2076
+ var decodedTypes = new Set();
2077
+ var unresolved = [];
2078
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
2079
+ try {
2080
+ for(var _iterator = keys[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
2081
+ var key = _step.value;
2082
+ var decoded = decodeFirestoreModelKey(key, manifest);
2083
+ if (decoded.unresolvedPrefixes.length > 0 || !decoded.leaf.modelType) {
2084
+ unresolved.push(key);
2085
+ } else {
2086
+ decodedTypes.add(decoded.leaf.modelType);
2087
+ }
2088
+ }
2089
+ } catch (err) {
2090
+ _didIteratorError = true;
2091
+ _iteratorError = err;
2092
+ } finally{
2093
+ try {
2094
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
2095
+ _iterator.return();
2096
+ }
2097
+ } finally{
2098
+ if (_didIteratorError) {
2099
+ throw _iteratorError;
2100
+ }
2101
+ }
2102
+ }
2103
+ if (unresolved.length > 0) {
2104
+ throw new CliError({
2105
+ message: "get-many: unable to resolve modelType for key(s): ".concat(unresolved.join(', '), ". Known prefixes: ").concat(manifestPrefixList(manifest), "."),
2106
+ code: 'INVALID_ARGUMENT'
2107
+ });
2108
+ }
2109
+ if (decodedTypes.size > 1) {
2110
+ throw new CliError({
2111
+ message: "get-many: all keys must belong to the same modelType. Got: ".concat(_to_consumable_array$4(decodedTypes).join(', '), ". Split into separate calls."),
2112
+ code: 'INVALID_ARGUMENT'
2113
+ });
2114
+ }
2115
+ var _decodedTypes = _sliced_to_array$3(decodedTypes, 1), modelType = _decodedTypes[0];
2116
+ return {
2117
+ modelType: modelType,
2118
+ keys: keys
2119
+ };
2120
+ }
2121
+ function manifestPrefixList(manifest) {
2122
+ var prefixes = manifest.map(function(e) {
2123
+ return e.collectionPrefix;
2124
+ }).sort();
2125
+ return prefixes.join(', ');
2126
+ }
2127
+
2128
+ function asyncGeneratorStep$e(gen, resolve, reject, _next, _throw, key, arg) {
2129
+ try {
2130
+ var info = gen[key](arg);
2131
+ var value = info.value;
2132
+ } catch (error) {
2133
+ reject(error);
2134
+ return;
2135
+ }
2136
+ if (info.done) {
2137
+ resolve(value);
2138
+ } else {
2139
+ Promise.resolve(value).then(_next, _throw);
2140
+ }
2141
+ }
2142
+ function _async_to_generator$e(fn) {
2143
+ return function() {
2144
+ var self = this, args = arguments;
2145
+ return new Promise(function(resolve, reject) {
2146
+ var gen = fn.apply(self, args);
2147
+ function _next(value) {
2148
+ asyncGeneratorStep$e(gen, resolve, reject, _next, _throw, "next", value);
2149
+ }
2150
+ function _throw(err) {
2151
+ asyncGeneratorStep$e(gen, resolve, reject, _next, _throw, "throw", err);
2152
+ }
2153
+ _next(undefined);
2154
+ });
2155
+ };
2156
+ }
2157
+ function _ts_generator$e(thisArg, body) {
2158
+ var f, y, t, _ = {
2159
+ label: 0,
2160
+ sent: function() {
2161
+ if (t[0] & 1) throw t[1];
2162
+ return t[1];
2163
+ },
2164
+ trys: [],
2165
+ ops: []
2166
+ }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty;
2167
+ return d(g, "next", {
2168
+ value: verb(0)
2169
+ }), d(g, "throw", {
2170
+ value: verb(1)
2171
+ }), d(g, "return", {
2172
+ value: verb(2)
2173
+ }), typeof Symbol === "function" && d(g, Symbol.iterator, {
2174
+ value: function() {
2175
+ return this;
2176
+ }
2177
+ }), g;
2178
+ function verb(n) {
2179
+ return function(v) {
2180
+ return step([
2181
+ n,
2182
+ v
2183
+ ]);
2184
+ };
2185
+ }
2186
+ function step(op) {
2187
+ if (f) throw new TypeError("Generator is already executing.");
2188
+ while(g && (g = 0, op[0] && (_ = 0)), _)try {
2189
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
2190
+ if (y = 0, t) op = [
2191
+ op[0] & 2,
2192
+ t.value
2193
+ ];
2194
+ switch(op[0]){
2195
+ case 0:
2196
+ case 1:
2197
+ t = op;
2198
+ break;
2199
+ case 4:
2200
+ _.label++;
2201
+ return {
2202
+ value: op[1],
2203
+ done: false
2204
+ };
2205
+ case 5:
2206
+ _.label++;
2207
+ y = op[1];
2208
+ op = [
2209
+ 0
2210
+ ];
2211
+ continue;
2212
+ case 7:
2213
+ op = _.ops.pop();
2214
+ _.trys.pop();
2215
+ continue;
2216
+ default:
2217
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
2218
+ _ = 0;
2219
+ continue;
2220
+ }
2221
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
2222
+ _.label = op[1];
2223
+ break;
2224
+ }
2225
+ if (op[0] === 6 && _.label < t[1]) {
2226
+ _.label = t[1];
2227
+ t = op;
2228
+ break;
2229
+ }
2230
+ if (t && _.label < t[2]) {
2231
+ _.label = t[2];
2232
+ _.ops.push(op);
2233
+ break;
2234
+ }
2235
+ if (t[2]) _.ops.pop();
2236
+ _.trys.pop();
2237
+ continue;
2238
+ }
2239
+ op = body.call(thisArg, _);
2240
+ } catch (e) {
2241
+ op = [
2242
+ 6,
2243
+ e
2244
+ ];
2245
+ y = 0;
2246
+ } finally{
2247
+ f = t = 0;
2248
+ }
2249
+ if (op[0] & 5) throw op[1];
2250
+ return {
2251
+ value: op[0] ? op[1] : void 0,
2252
+ done: true
2253
+ };
2254
+ }
2255
+ }
2256
+ /**
2257
+ * Top-level `get <modelOrKey> [key]` command.
2258
+ *
2259
+ * Reads a single Firestore document via the typed model-access endpoint. The `model` arg is optional:
2260
+ * when only one positional is supplied, the CLI resolves the modelType from the key's leading
2261
+ * collection-name prefix via {@link decodeFirestoreModelKey}. The two-positional form passes the
2262
+ * explicit `modelType` straight through.
2263
+ *
2264
+ * Backend: `GET <apiBaseUrl>/model/<modelType>/get?key=<key>` (ModelApiController.getOne).
2265
+ */ var getCommand = {
2266
+ command: 'get <modelOrKey> [key]',
2267
+ describe: 'Read a document by key. ModelType is inferred from the key prefix when only one positional is supplied.',
2268
+ builder: function builder(yargs) {
2269
+ return yargs.positional('modelOrKey', {
2270
+ type: 'string',
2271
+ describe: 'Full key (e.g. "jws/abc123") or model name when a second positional is supplied.'
2272
+ }).positional('key', {
2273
+ type: 'string',
2274
+ describe: 'Document key when the first positional is a model name.'
2275
+ });
2276
+ },
2277
+ handler: function handler(argv) {
2278
+ return _async_to_generator$e(function() {
2279
+ var context, _parseGetArgs, modelType, key, result, e;
2280
+ return _ts_generator$e(this, function(_state) {
2281
+ switch(_state.label){
2282
+ case 0:
2283
+ _state.trys.push([
2284
+ 0,
2285
+ 2,
2286
+ ,
2287
+ 3
2288
+ ]);
2289
+ context = requireCliContext();
2290
+ _parseGetArgs = parseGetArgs({
2291
+ modelOrKey: typeof argv.modelOrKey === 'string' ? argv.modelOrKey : undefined,
2292
+ key: typeof argv.key === 'string' ? argv.key : undefined,
2293
+ manifest: context.modelManifest
2294
+ }), modelType = _parseGetArgs.modelType, key = _parseGetArgs.key;
2295
+ return [
2296
+ 4,
2297
+ context.getModel(modelType, key)
2298
+ ];
2299
+ case 1:
2300
+ result = _state.sent();
2301
+ outputResult(result);
2302
+ return [
2303
+ 3,
2304
+ 3
2305
+ ];
2306
+ case 2:
2307
+ e = _state.sent();
2308
+ outputError(e);
2309
+ process.exit(1);
2310
+ return [
2311
+ 3,
2312
+ 3
2313
+ ];
2314
+ case 3:
2315
+ return [
2316
+ 2
2317
+ ];
2318
+ }
2319
+ });
2320
+ })();
2321
+ }
2322
+ };
2323
+
2324
+ function asyncGeneratorStep$d(gen, resolve, reject, _next, _throw, key, arg) {
2325
+ try {
2326
+ var info = gen[key](arg);
2327
+ var value = info.value;
2328
+ } catch (error) {
2329
+ reject(error);
2330
+ return;
2331
+ }
2332
+ if (info.done) {
2333
+ resolve(value);
2334
+ } else {
2335
+ Promise.resolve(value).then(_next, _throw);
2336
+ }
2337
+ }
2338
+ function _async_to_generator$d(fn) {
2339
+ return function() {
2340
+ var self = this, args = arguments;
2341
+ return new Promise(function(resolve, reject) {
2342
+ var gen = fn.apply(self, args);
2343
+ function _next(value) {
2344
+ asyncGeneratorStep$d(gen, resolve, reject, _next, _throw, "next", value);
2345
+ }
2346
+ function _throw(err) {
2347
+ asyncGeneratorStep$d(gen, resolve, reject, _next, _throw, "throw", err);
2348
+ }
2349
+ _next(undefined);
2350
+ });
2351
+ };
2352
+ }
2353
+ function _ts_generator$d(thisArg, body) {
2354
+ var f, y, t, _ = {
2355
+ label: 0,
2356
+ sent: function() {
2357
+ if (t[0] & 1) throw t[1];
2358
+ return t[1];
2359
+ },
2360
+ trys: [],
2361
+ ops: []
2362
+ }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty;
2363
+ return d(g, "next", {
2364
+ value: verb(0)
2365
+ }), d(g, "throw", {
2366
+ value: verb(1)
2367
+ }), d(g, "return", {
2368
+ value: verb(2)
2369
+ }), typeof Symbol === "function" && d(g, Symbol.iterator, {
2370
+ value: function() {
2371
+ return this;
2372
+ }
2373
+ }), g;
2374
+ function verb(n) {
2375
+ return function(v) {
2376
+ return step([
2377
+ n,
2378
+ v
2379
+ ]);
2380
+ };
2381
+ }
2382
+ function step(op) {
2383
+ if (f) throw new TypeError("Generator is already executing.");
2384
+ while(g && (g = 0, op[0] && (_ = 0)), _)try {
2385
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
2386
+ if (y = 0, t) op = [
2387
+ op[0] & 2,
2388
+ t.value
2389
+ ];
2390
+ switch(op[0]){
2391
+ case 0:
2392
+ case 1:
2393
+ t = op;
2394
+ break;
2395
+ case 4:
2396
+ _.label++;
2397
+ return {
2398
+ value: op[1],
2399
+ done: false
2400
+ };
2401
+ case 5:
2402
+ _.label++;
2403
+ y = op[1];
2404
+ op = [
2405
+ 0
2406
+ ];
2407
+ continue;
2408
+ case 7:
2409
+ op = _.ops.pop();
2410
+ _.trys.pop();
2411
+ continue;
2412
+ default:
2413
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
2414
+ _ = 0;
2415
+ continue;
2416
+ }
2417
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
2418
+ _.label = op[1];
2419
+ break;
2420
+ }
2421
+ if (op[0] === 6 && _.label < t[1]) {
2422
+ _.label = t[1];
2423
+ t = op;
2424
+ break;
2425
+ }
2426
+ if (t && _.label < t[2]) {
2427
+ _.label = t[2];
2428
+ _.ops.push(op);
2429
+ break;
2430
+ }
2431
+ if (t[2]) _.ops.pop();
2432
+ _.trys.pop();
2433
+ continue;
2434
+ }
2435
+ op = body.call(thisArg, _);
2436
+ } catch (e) {
2437
+ op = [
2438
+ 6,
2439
+ e
2440
+ ];
2441
+ y = 0;
2442
+ } finally{
2443
+ f = t = 0;
1437
2444
  }
2445
+ if (op[0] & 5) throw op[1];
2446
+ return {
2447
+ value: op[0] ? op[1] : void 0,
2448
+ done: true
2449
+ };
1438
2450
  }
1439
- return result;
1440
2451
  }
1441
2452
  /**
1442
- * Rewrites the persisted (short) keys in `data` to the long-name form
1443
- * declared in the model's manifest entry. Recurses into nested object-array
1444
- * and sub-object fields when the manifest captured a nested field map.
2453
+ * Top-level `get-many <firstArg> [rest..]` command.
1445
2454
  *
1446
- * Returns the input untouched when `modelType` is not in the manifest, when
1447
- * the model has no fields, or when the input is not a plain object/array.
1448
- * Unknown keys, primitives, `Date`, `null`, and `undefined` pass through
1449
- * unchanged.
2455
+ * Batch-reads up to 50 Firestore documents in a single request. The first positional can either
2456
+ * be an explicit modelType (followed by ≥1 keys) or a full key (followed by additional keys whose
2457
+ * prefixes must resolve to the same modelType).
1450
2458
  *
1451
- * @param modelType - the model identifier (`modelType`, `identityConst`,
1452
- * or `collectionPrefix`) used to look up the rewrite map.
1453
- * @param data - the value to rewrite (typically a `read`/`query` response
1454
- * payload).
1455
- * @param manifest - generated model manifest.
1456
- * @returns the rewritten value, or `data` unchanged when no rewrite applies.
1457
- * @__NO_SIDE_EFFECTS__
1458
- */ function expandModelKeys(modelType, data, manifest) {
1459
- var entry = findCliModelManifestEntry(modelType, manifest);
1460
- if (!entry) return data;
1461
- return rewriteWithFields(data, entry.fields);
1462
- }
1463
- function rewriteWithFields(value, fields) {
1464
- if (Array.isArray(value)) {
1465
- return value.map(function(item) {
1466
- return rewriteWithFields(item, fields);
1467
- });
1468
- }
1469
- if (!isPlainObject(value)) return value;
1470
- var fieldByName = new Map();
1471
- var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1472
- try {
1473
- for(var _iterator = fields[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1474
- var field = _step.value;
1475
- fieldByName.set(field.name, field);
1476
- }
1477
- } catch (err) {
1478
- _didIteratorError = true;
1479
- _iteratorError = err;
1480
- } finally{
1481
- try {
1482
- if (!_iteratorNormalCompletion && _iterator.return != null) {
1483
- _iterator.return();
1484
- }
1485
- } finally{
1486
- if (_didIteratorError) {
1487
- throw _iteratorError;
1488
- }
1489
- }
1490
- }
1491
- var out = {};
1492
- var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
1493
- try {
1494
- for(var _iterator1 = Object.entries(value)[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
1495
- var _step_value = _sliced_to_array$3(_step1.value, 2), key = _step_value[0], raw = _step_value[1];
1496
- var field1 = fieldByName.get(key);
1497
- if (!field1) {
1498
- out[key] = raw;
1499
- continue;
1500
- }
1501
- var longKey = field1.longName.length > 0 ? field1.longName : key;
1502
- out[longKey] = rewriteFieldValue(raw, field1);
1503
- }
1504
- } catch (err) {
1505
- _didIteratorError1 = true;
1506
- _iteratorError1 = err;
1507
- } finally{
1508
- try {
1509
- if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
1510
- _iterator1.return();
1511
- }
1512
- } finally{
1513
- if (_didIteratorError1) {
1514
- throw _iteratorError1;
1515
- }
1516
- }
1517
- }
1518
- return out;
1519
- }
1520
- function rewriteFieldValue(value, field) {
1521
- var nested = field.nestedFields;
1522
- if (!nested || nested.length === 0) return value;
1523
- if (field.nestedIsArray) {
1524
- if (!Array.isArray(value)) return value;
1525
- return value.map(function(item) {
1526
- return rewriteWithFields(item, nested);
2459
+ * Backend: `POST <apiBaseUrl>/model/<modelType>/get` with body `{ keys }` (ModelApiController.getMany).
2460
+ */ var getManyCommand = {
2461
+ command: 'get-many <firstArg> [rest..]',
2462
+ describe: 'Read up to 50 documents by key. ModelType is inferred from key prefixes when they all agree.',
2463
+ builder: function builder(yargs) {
2464
+ return yargs.positional('firstArg', {
2465
+ type: 'string',
2466
+ describe: 'Full key (e.g. "jws/abc") or model name when the remaining positionals are bare ids.'
2467
+ }).positional('rest', {
2468
+ type: 'string',
2469
+ array: true,
2470
+ default: [],
2471
+ describe: 'Additional keys (or bare ids when the first positional is a model name).'
1527
2472
  });
2473
+ },
2474
+ handler: function handler(argv) {
2475
+ return _async_to_generator$d(function() {
2476
+ var context, _parseGetManyArgs, modelType, keys, result, e;
2477
+ return _ts_generator$d(this, function(_state) {
2478
+ switch(_state.label){
2479
+ case 0:
2480
+ _state.trys.push([
2481
+ 0,
2482
+ 2,
2483
+ ,
2484
+ 3
2485
+ ]);
2486
+ context = requireCliContext();
2487
+ _parseGetManyArgs = parseGetManyArgs({
2488
+ firstArg: typeof argv.firstArg === 'string' ? argv.firstArg : undefined,
2489
+ rest: Array.isArray(argv.rest) ? argv.rest : [],
2490
+ manifest: context.modelManifest
2491
+ }), modelType = _parseGetManyArgs.modelType, keys = _parseGetManyArgs.keys;
2492
+ return [
2493
+ 4,
2494
+ context.getMultipleModels(modelType, keys)
2495
+ ];
2496
+ case 1:
2497
+ result = _state.sent();
2498
+ outputResult(result);
2499
+ return [
2500
+ 3,
2501
+ 3
2502
+ ];
2503
+ case 2:
2504
+ e = _state.sent();
2505
+ outputError(e);
2506
+ process.exit(1);
2507
+ return [
2508
+ 3,
2509
+ 3
2510
+ ];
2511
+ case 3:
2512
+ return [
2513
+ 2
2514
+ ];
2515
+ }
2516
+ });
2517
+ })();
1528
2518
  }
1529
- if (!isPlainObject(value)) return value;
1530
- return rewriteWithFields(value, nested);
1531
- }
1532
- function isPlainObject(value) {
1533
- if (value === null || (typeof value === "undefined" ? "undefined" : _type_of$1(value)) !== 'object') return false;
1534
- if (Array.isArray(value)) return false;
1535
- if (_instanceof$4(value, Date)) return false;
1536
- // Objects from JSON.parse have Object.prototype as their proto. Anything
1537
- // exotic (Map, Set, Buffer, class instances) we leave untouched.
1538
- var proto = Object.getPrototypeOf(value);
1539
- return proto === Object.prototype || proto === null;
1540
- }
2519
+ };
1541
2520
 
1542
2521
  function asyncGeneratorStep$c(gen, resolve, reject, _next, _throw, key, arg) {
1543
2522
  try {
@@ -2201,7 +3180,8 @@ function _ts_generator$b(thisArg, body) {
2201
3180
  }
2202
3181
  }
2203
3182
  /**
2204
- * Fetches the OIDC discovery document for the given issuer, trying these candidates in order:
3183
+ * Builds the ordered list of `.well-known/openid-configuration` URLs the CLI probes when
3184
+ * discovering OIDC metadata.
2205
3185
  *
2206
3186
  * 1. `<issuer>/.well-known/openid-configuration` (OpenID Connect Discovery 1.0).
2207
3187
  * 2. `<issuer-origin>/.well-known/openid-configuration` (host-rooted; matches projects that
@@ -2209,33 +3189,48 @@ function _ts_generator$b(thisArg, body) {
2209
3189
  * sub-path — e.g. demo's `OidcWellKnownController`).
2210
3190
  * 3. `<fallbackBaseUrl>/.well-known/openid-configuration` when supplied and not already covered.
2211
3191
  *
3192
+ * Exported so diagnostic surfaces (e.g. `doctor`) can show the exact URLs the discovery step
3193
+ * tried — without re-implementing the candidate ordering.
3194
+ *
3195
+ * @param input - The discovery request.
3196
+ * @param input.issuer - The OIDC issuer URL whose `.well-known/openid-configuration` is fetched first.
3197
+ * @param input.fallbackBaseUrl - Optional sibling base URL appended after the issuer-prefixed and origin-rooted candidates.
3198
+ * @returns The candidate URL list in probe order, de-duplicated.
3199
+ */ function buildOidcDiscoveryCandidates(input) {
3200
+ var candidates = [
3201
+ "".concat(trimSlash(input.issuer), "/.well-known/openid-configuration")
3202
+ ];
3203
+ try {
3204
+ var originCandidate = "".concat(new URL(input.issuer).origin, "/.well-known/openid-configuration");
3205
+ if (!candidates.includes(originCandidate)) {
3206
+ candidates.push(originCandidate);
3207
+ }
3208
+ } catch (unused) {
3209
+ // Issuer URL didn't parse — skip the origin-rooted candidate and let the explicit fallback handle it.
3210
+ }
3211
+ if (input.fallbackBaseUrl) {
3212
+ var fallbackCandidate = "".concat(trimSlash(input.fallbackBaseUrl), "/.well-known/openid-configuration");
3213
+ if (!candidates.includes(fallbackCandidate)) {
3214
+ candidates.push(fallbackCandidate);
3215
+ }
3216
+ }
3217
+ return candidates;
3218
+ }
3219
+ /**
3220
+ * Fetches the OIDC discovery document for the given issuer, trying the candidates returned by
3221
+ * {@link buildOidcDiscoveryCandidates} in order.
3222
+ *
2212
3223
  * @param input - The discovery request.
2213
3224
  * @param input.issuer - The OIDC issuer URL whose `.well-known/openid-configuration` is fetched first.
2214
3225
  * @param input.fallbackBaseUrl - Optional sibling base URL tried after the issuer-prefixed and origin-rooted candidates.
2215
3226
  * @returns The parsed {@link OidcDiscoveryMetadata}. Throws a {@link CliError} (`OIDC_DISCOVERY_FAILED`) when every candidate fails.
2216
3227
  */ function discoverOidcMetadata(input) {
2217
3228
  return _async_to_generator$b(function() {
2218
- var _ref, candidates, originCandidate, fallbackCandidate, lastError, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, url, res, e, err;
3229
+ var _ref, candidates, lastError, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, url, res, e, err;
2219
3230
  return _ts_generator$b(this, function(_state) {
2220
3231
  switch(_state.label){
2221
3232
  case 0:
2222
- candidates = [
2223
- "".concat(trimSlash(input.issuer), "/.well-known/openid-configuration")
2224
- ];
2225
- try {
2226
- originCandidate = "".concat(new URL(input.issuer).origin, "/.well-known/openid-configuration");
2227
- if (!candidates.includes(originCandidate)) {
2228
- candidates.push(originCandidate);
2229
- }
2230
- } catch (unused) {
2231
- // Issuer URL didn't parse — skip the origin-rooted candidate and let the explicit fallback handle it.
2232
- }
2233
- if (input.fallbackBaseUrl) {
2234
- fallbackCandidate = "".concat(trimSlash(input.fallbackBaseUrl), "/.well-known/openid-configuration");
2235
- if (!candidates.includes(fallbackCandidate)) {
2236
- candidates.push(fallbackCandidate);
2237
- }
2238
- }
3233
+ candidates = buildOidcDiscoveryCandidates(input);
2239
3234
  _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
2240
3235
  _state.label = 1;
2241
3236
  case 1:
@@ -2292,7 +3287,7 @@ function _ts_generator$b(thisArg, body) {
2292
3287
  ];
2293
3288
  case 7:
2294
3289
  e = _state.sent();
2295
- lastError = _instanceof$3(e, Error) ? e : new Error(String(e));
3290
+ lastError = new Error("OIDC discovery failed at ".concat(url, ": ").concat(_instanceof$3(e, Error) ? e.message : String(e)));
2296
3291
  return [
2297
3292
  3,
2298
3293
  8
@@ -2331,7 +3326,7 @@ function _ts_generator$b(thisArg, body) {
2331
3326
  ];
2332
3327
  case 12:
2333
3328
  throw new CliError({
2334
- message: (_ref = lastError === null || lastError === void 0 ? void 0 : lastError.message) !== null && _ref !== void 0 ? _ref : 'OIDC discovery failed',
3329
+ message: (_ref = lastError === null || lastError === void 0 ? void 0 : lastError.message) !== null && _ref !== void 0 ? _ref : "OIDC discovery failed for all candidates: ".concat(candidates.join(', ')),
2335
3330
  code: 'OIDC_DISCOVERY_FAILED',
2336
3331
  suggestion: 'Verify the env oidcIssuer URL is reachable and serves /.well-known/openid-configuration.'
2337
3332
  });
@@ -2726,14 +3721,24 @@ function _ts_generator$a(thisArg, body) {
2726
3721
  /**
2727
3722
  * Builds the authorization URL the user opens in a browser to start the PKCE flow.
2728
3723
  *
2729
- * Resolves the user-facing endpoint by preferring `appClientUrl` (rebases the discovered
2730
- * authorization endpoint onto that origin) over `apiBaseUrl` (`/oidc/login/client` shortcut),
2731
- * and finally falls back to the discovered `authorizationEndpoint` itself.
3724
+ * The user-facing endpoint is the discovered `authorizationEndpoint` (typically `/oidc/auth`)
3725
+ * with its origin optionally rebased. The rebase origin is the first non-empty value among
3726
+ * `appClientUrl` `oidcIssuer` origin `apiBaseUrl` origin. In a typical single-host
3727
+ * deployment all three resolve to the same origin and the rebase is a no-op; in a split-host
3728
+ * setup (frontend dev server proxying `/oidc/**` to the API) `appClientUrl` redirects the user
3729
+ * through the frontend. When none of the three is provided, the discovered endpoint is used
3730
+ * unchanged.
3731
+ *
3732
+ * Always lands at the actual authorization endpoint so oidc-provider can create an interaction
3733
+ * and redirect to the app login page with a `uid`. (Earlier versions targeted a convenience
3734
+ * `/oidc/login/client` redirect that forwarded query params to the app without creating an
3735
+ * interaction — that branch is gone.)
2732
3736
  *
2733
3737
  * @param input - The authorization URL inputs.
2734
3738
  * @param input.authorizationEndpoint - The authorization endpoint discovered from OIDC metadata.
2735
- * @param input.apiBaseUrl - Optional API base URL; when set without `appClientUrl`, the URL is built against `<apiBaseUrl>/oidc/login/client`.
2736
- * @param input.appClientUrl - Optional frontend origin to rebase the authorization endpoint onto. Takes precedence over `apiBaseUrl`.
3739
+ * @param input.appClientUrl - Optional client origin to rebase the authorization endpoint onto. Takes precedence over `oidcIssuer` and `apiBaseUrl`.
3740
+ * @param input.oidcIssuer - Optional OIDC issuer URL; falls back to its origin as the rebase target when `appClientUrl` is missing.
3741
+ * @param input.apiBaseUrl - Optional API base URL; falls back to its origin as the rebase target when neither `appClientUrl` nor `oidcIssuer` is set.
2737
3742
  * @param input.clientId - The OAuth client ID.
2738
3743
  * @param input.redirectUri - The redirect URI registered with the OAuth client.
2739
3744
  * @param input.scopes - Space-separated scope list. Defaults to {@link DEFAULT_CLI_OIDC_SCOPES}.
@@ -2743,15 +3748,22 @@ function _ts_generator$a(thisArg, body) {
2743
3748
  * @__NO_SIDE_EFFECTS__
2744
3749
  */ function buildAuthorizationUrl(input) {
2745
3750
  var _input_scopes;
3751
+ var resolvedScope = (_input_scopes = input.scopes) !== null && _input_scopes !== void 0 ? _input_scopes : DEFAULT_CLI_OIDC_SCOPES;
2746
3752
  var authParams = {
2747
3753
  response_type: 'code',
2748
3754
  client_id: input.clientId,
2749
3755
  redirect_uri: input.redirectUri,
2750
- scope: (_input_scopes = input.scopes) !== null && _input_scopes !== void 0 ? _input_scopes : DEFAULT_CLI_OIDC_SCOPES,
3756
+ scope: resolvedScope,
2751
3757
  code_challenge: input.codeChallenge,
2752
3758
  code_challenge_method: 'S256',
2753
3759
  state: input.state
2754
3760
  };
3761
+ // oidc-provider's check_scope middleware silently strips `offline_access` unless the
3762
+ // auth request also includes `prompt=consent`. Auto-add it so refresh tokens are
3763
+ // actually issued whenever the CLI requests offline access.
3764
+ if (resolvedScope.split(/\s+/).includes('offline_access')) {
3765
+ authParams.prompt = 'consent';
3766
+ }
2755
3767
  if (input.requestedSessionTtlSeconds != null) {
2756
3768
  if (!Number.isInteger(input.requestedSessionTtlSeconds) || input.requestedSessionTtlSeconds <= 0) {
2757
3769
  throw new CliError({
@@ -2761,19 +3773,17 @@ function _ts_generator$a(thisArg, body) {
2761
3773
  }
2762
3774
  authParams.dbx_session_ttl = String(input.requestedSessionTtlSeconds);
2763
3775
  }
2764
- var endpoint;
2765
- if (input.appClientUrl) {
2766
- endpoint = rebaseUrlOrigin({
2767
- url: input.authorizationEndpoint,
2768
- originUrl: input.appClientUrl
2769
- });
2770
- } else if (input.apiBaseUrl) {
2771
- endpoint = "".concat(input.apiBaseUrl.replace(/\/+$/, ''), "/oidc/login/client");
2772
- } else {
2773
- endpoint = input.authorizationEndpoint;
2774
- }
3776
+ var rebaseOrigin = resolveAuthorizationRebaseOrigin({
3777
+ appClientUrl: input.appClientUrl,
3778
+ oidcIssuer: input.oidcIssuer,
3779
+ apiBaseUrl: input.apiBaseUrl
3780
+ });
3781
+ var endpoint = rebaseOrigin ? rebaseUrlOrigin({
3782
+ url: input.authorizationEndpoint,
3783
+ originUrl: rebaseOrigin
3784
+ }) : input.authorizationEndpoint;
2775
3785
  // Merge into the existing query string (preserving any params already on the endpoint) so
2776
- // a pre-baked endpoint like `/login/client?source=cli` survives unchanged.
3786
+ // a pre-baked endpoint like `/oidc/auth?source=cli` survives unchanged.
2777
3787
  var url = new URL(endpoint);
2778
3788
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
2779
3789
  try {
@@ -2797,6 +3807,31 @@ function _ts_generator$a(thisArg, body) {
2797
3807
  }
2798
3808
  return url.toString();
2799
3809
  }
3810
+ /**
3811
+ * Picks the origin used to rebase the discovered authorization endpoint, in priority order:
3812
+ * 1. `appClientUrl` (verbatim — the explicit override)
3813
+ * 2. `oidcIssuer` (parsed `origin`, e.g. `https://api.example.com/oidc` → `https://api.example.com`)
3814
+ * 3. `apiBaseUrl` (parsed `origin`, e.g. `https://api.example.com/api` → `https://api.example.com`)
3815
+ *
3816
+ * Returns `undefined` when none is set or every candidate fails to parse; the caller should then
3817
+ * use the discovered endpoint unchanged.
3818
+ */ function resolveAuthorizationRebaseOrigin(input) {
3819
+ var result;
3820
+ if (input.appClientUrl) {
3821
+ result = input.appClientUrl;
3822
+ } else {
3823
+ var _input_oidcIssuer;
3824
+ var fallbackSource = (_input_oidcIssuer = input.oidcIssuer) !== null && _input_oidcIssuer !== void 0 ? _input_oidcIssuer : input.apiBaseUrl;
3825
+ if (fallbackSource) {
3826
+ try {
3827
+ result = new URL(fallbackSource).origin;
3828
+ } catch (unused) {
3829
+ // Fall through with result undefined
3830
+ }
3831
+ }
3832
+ }
3833
+ return result;
3834
+ }
2800
3835
  /**
2801
3836
  * Returns `url` with its origin replaced by the origin of `originUrl`. The path and search of
2802
3837
  * `url` are preserved. When `originUrl` is empty/missing or either URL fails to parse, returns
@@ -3604,6 +4639,7 @@ function maskEnv$1(env) {
3604
4639
  }
3605
4640
  url = buildAuthorizationUrl({
3606
4641
  authorizationEndpoint: meta.authorization_endpoint,
4642
+ oidcIssuer: env.oidcIssuer,
3607
4643
  apiBaseUrl: env.apiBaseUrl,
3608
4644
  appClientUrl: env.appClientUrl,
3609
4645
  clientId: env.clientId,
@@ -4351,7 +5387,7 @@ function _ts_generator$8(thisArg, body) {
4351
5387
  function(param) {
4352
5388
  var env = param.env;
4353
5389
  return _async_to_generator$8(function() {
4354
- var meta, e;
5390
+ var candidates, meta, e;
4355
5391
  return _ts_generator$8(this, function(_state) {
4356
5392
  switch(_state.label){
4357
5393
  case 0:
@@ -4365,6 +5401,10 @@ function _ts_generator$8(thisArg, body) {
4365
5401
  }
4366
5402
  ];
4367
5403
  }
5404
+ candidates = buildOidcDiscoveryCandidates({
5405
+ issuer: env.oidcIssuer,
5406
+ fallbackBaseUrl: env.apiBaseUrl
5407
+ });
4368
5408
  _state.label = 1;
4369
5409
  case 1:
4370
5410
  _state.trys.push([
@@ -4388,6 +5428,7 @@ function _ts_generator$8(thisArg, body) {
4388
5428
  name: 'oidc-discovery-reachable',
4389
5429
  ok: true,
4390
5430
  detail: {
5431
+ candidates: candidates,
4391
5432
  authorization_endpoint: meta.authorization_endpoint,
4392
5433
  token_endpoint: meta.token_endpoint
4393
5434
  }
@@ -4401,6 +5442,7 @@ function _ts_generator$8(thisArg, body) {
4401
5442
  name: 'oidc-discovery-reachable',
4402
5443
  ok: false,
4403
5444
  detail: {
5445
+ candidates: candidates,
4404
5446
  error: _instanceof$2(e, Error) ? e.message : String(e)
4405
5447
  },
4406
5448
  suggestion: 'Verify the env oidcIssuer URL and that the API is running.'
@@ -4506,7 +5548,10 @@ function _ts_generator$8(thisArg, body) {
4506
5548
  {
4507
5549
  name: 'token-refresh-round-trip',
4508
5550
  ok: false,
4509
- suggestion: "Run `".concat(cliName, " auth login --env ").concat(envName, "`.")
5551
+ detail: {
5552
+ reason: 'no-refresh-token'
5553
+ },
5554
+ suggestion: 'No refresh token cached for env "'.concat(envName, '". Run `').concat(cliName, " auth login --env ").concat(envName, "` — if the env's scopes omit `offline_access`, the OIDC provider may not issue one.")
4510
5555
  }
4511
5556
  ];
4512
5557
  }
@@ -4583,6 +5628,7 @@ function _ts_generator$8(thisArg, body) {
4583
5628
  }
4584
5629
  ];
4585
5630
  }
5631
+ url = "".concat(env.apiBaseUrl.replace(/\/+$/, '')).concat(CALL_MODEL_API_PATH);
4586
5632
  _state.label = 1;
4587
5633
  case 1:
4588
5634
  _state.trys.push([
@@ -4591,7 +5637,6 @@ function _ts_generator$8(thisArg, body) {
4591
5637
  ,
4592
5638
  4
4593
5639
  ]);
4594
- url = "".concat(env.apiBaseUrl.replace(/\/+$/, '')).concat(CALL_MODEL_API_PATH);
4595
5640
  return [
4596
5641
  4,
4597
5642
  fetch(url, {
@@ -4606,6 +5651,7 @@ function _ts_generator$8(thisArg, body) {
4606
5651
  name: 'api-base-url-reachable',
4607
5652
  ok: res.status < 500,
4608
5653
  detail: {
5654
+ url: url,
4609
5655
  status: res.status
4610
5656
  }
4611
5657
  }
@@ -4618,6 +5664,7 @@ function _ts_generator$8(thisArg, body) {
4618
5664
  name: 'api-base-url-reachable',
4619
5665
  ok: false,
4620
5666
  detail: {
5667
+ url: url,
4621
5668
  error: _instanceof$2(e, Error) ? e.message : String(e)
4622
5669
  },
4623
5670
  suggestion: 'Verify the API is running at apiBaseUrl.'
@@ -6129,7 +7176,8 @@ function _ts_generator$6(thisArg, body) {
6129
7176
  cliName: input.cliName,
6130
7177
  envName: envName,
6131
7178
  env: env,
6132
- accessToken: entry.accessToken
7179
+ accessToken: entry.accessToken,
7180
+ modelManifest: input.modelManifest
6133
7181
  }));
6134
7182
  return [
6135
7183
  3,
@@ -7276,10 +8324,16 @@ function _ts_generator$2(thisArg, body) {
7276
8324
  if (input.modelManifest && input.disableModelInfo !== true) {
7277
8325
  builtInConfigCommands.push(buildModelInfoCommand(input.modelManifest));
7278
8326
  }
8327
+ if (input.modelManifest && input.disableModelDecode !== true) {
8328
+ builtInConfigCommands.push(buildModelDecodeCommand(input.modelManifest));
8329
+ }
7279
8330
  var allConfigCommands = _to_consumable_array$1(builtInConfigCommands).concat(_to_consumable_array$1((_input_configCommands = input.configCommands) !== null && _input_configCommands !== void 0 ? _input_configCommands : []));
7280
8331
  var builtInApiCommands = input.disableCallPassthrough ? [] : [
7281
8332
  callPassthroughCommand
7282
8333
  ];
8334
+ if (input.disableModelGet !== true) {
8335
+ builtInApiCommands.push(getCommand, getManyCommand);
8336
+ }
7283
8337
  var allApiCommands = _to_consumable_array$1(builtInApiCommands).concat(_to_consumable_array$1((_input_apiCommands = input.apiCommands) !== null && _input_apiCommands !== void 0 ? _input_apiCommands : []));
7284
8338
  var skipCommandNames = new Set(allConfigCommands.map(function(c) {
7285
8339
  return commandName(c);
@@ -7331,7 +8385,8 @@ function _ts_generator$2(thisArg, body) {
7331
8385
  createAuthMiddleware({
7332
8386
  cliName: cliName,
7333
8387
  skipCommands: skipCommandNames,
7334
- defaultEnvs: defaultEnvs
8388
+ defaultEnvs: defaultEnvs,
8389
+ modelManifest: input.modelManifest
7335
8390
  }),
7336
8391
  createOutputMiddleware({
7337
8392
  cliName: cliName,
@@ -7883,6 +8938,7 @@ function buildModelCommand(model, entries, context) {
7883
8938
  }
7884
8939
  }
7885
8940
  }
8941
+ yargs.command(buildPerModelGetCommand(model));
7886
8942
  hideGlobalOptions(yargs, context.hideOnFocus);
7887
8943
  return yargs.demandCommand(1, 'Please specify an action.');
7888
8944
  },
@@ -7891,6 +8947,71 @@ function buildModelCommand(model, entries, context) {
7891
8947
  }
7892
8948
  };
7893
8949
  }
8950
+ /**
8951
+ * Synthetic per-model `get <key>` sub-command appended to every model's command tree.
8952
+ *
8953
+ * The parent `model <name>` already fixes the `modelType`, so this command just passes the bare
8954
+ * `key` positional through to `context.getModel(modelType, key)`. Supports both the full
8955
+ * `<prefix>/<id>` form and a bare doc id (when the user knows the modelType from the parent).
8956
+ */ function buildPerModelGetCommand(model) {
8957
+ return {
8958
+ command: 'get <key>',
8959
+ describe: "Read a single ".concat(model, " document by key."),
8960
+ builder: function builder(yargs) {
8961
+ return yargs.positional('key', {
8962
+ type: 'string',
8963
+ describe: "Firestore key for the ".concat(model, " document (full `prefix/id` or bare id).")
8964
+ });
8965
+ },
8966
+ handler: function handler(argv) {
8967
+ return _async_to_generator$1(function() {
8968
+ var ctx, key, result, e;
8969
+ return _ts_generator$1(this, function(_state) {
8970
+ switch(_state.label){
8971
+ case 0:
8972
+ _state.trys.push([
8973
+ 0,
8974
+ 2,
8975
+ ,
8976
+ 3
8977
+ ]);
8978
+ ctx = requireCliContext();
8979
+ key = typeof argv.key === 'string' ? argv.key.trim() : '';
8980
+ if (key.length === 0) {
8981
+ throw new CliError({
8982
+ message: "get: missing required <key> positional for model '".concat(model, "'."),
8983
+ code: 'INVALID_ARGUMENT'
8984
+ });
8985
+ }
8986
+ return [
8987
+ 4,
8988
+ ctx.getModel(model, key)
8989
+ ];
8990
+ case 1:
8991
+ result = _state.sent();
8992
+ outputResult(result);
8993
+ return [
8994
+ 3,
8995
+ 3
8996
+ ];
8997
+ case 2:
8998
+ e = _state.sent();
8999
+ outputError(e);
9000
+ process.exit(1);
9001
+ return [
9002
+ 3,
9003
+ 3
9004
+ ];
9005
+ case 3:
9006
+ return [
9007
+ 2
9008
+ ];
9009
+ }
9010
+ });
9011
+ })();
9012
+ }
9013
+ };
9014
+ }
7894
9015
  function buildEntryCommand(entry, context) {
7895
9016
  var _oneLineDescription;
7896
9017
  var action = entry.specifier && entry.specifier !== '_' ? "".concat(entry.verb, "-").concat(entry.specifier) : entry.verb;
@@ -8832,4 +9953,4 @@ function printPaginatedOutput(input) {
8832
9953
  })();
8833
9954
  }
8834
9955
 
8835
- export { CALL_MODEL_API_PATH, CliError, DEFAULT_CLI_OIDC_SCOPES, DEFAULT_CLI_REDIRECT_URI, DEFAULT_CLI_SECRET_PATTERNS, DEFAULT_MANIFEST_HELP_DATA_FORMAT, DEFAULT_MANIFEST_HELP_MODE, DEFAULT_MANIFEST_MODEL_COMMAND_NAME, DEFAULT_MODEL_INFO_COMMAND_NAME, DUMP_MERGE_MODES, DUMP_OUTPUT_MODES, MODEL_WRITE_OIDC_SCOPES, MULTIPLE_PAGES_OUTPUT_MODES, PROMPT_CANCELLED_ERROR_CODE, STANDARD_GLOBAL_OPTION_NAMES, applyEnvVarOverrides, buildAuthorizationUrl, buildCliPaths, buildDumpFilePath, buildErrorOutput, buildManifestCommands, buildModelInfoCommand, callModelOverHttp, callPassthroughCommand, configureCliErrorMapper, configureCliSecretPatterns, configureOutputOptions, createAuthCommand, createAuthMiddleware, createCallModelCommand, createCli, createCliContext, createCliTokenCacheStore, createContextSlot, createDoctorCommand, createEnvCommand, createOutputCommand, createOutputMiddleware, defaultDoctorChecks, detectDataHelpFormat, detectHelpMode, discoverOidcMetadata, dumpTimestamp, exchangeAuthorizationCode, expandModelKeys, fetchUserInfo, filterReadOnlyModelScopes, findCliEnvDefault, findCliModelManifestEntry, generateOAuthState, generatePkceMaterial, getCliContext, getOutputOptions, isCliEnvConfigComplete, isTokenExpired, loadCliConfig, maskSecret, mergeCliConfig, mergeCliEnvWithDefault, mergeOutputConfig, openStreamingDump, outputError, outputResult, parsePastedRedirect, pickFields, promptLine, refreshAccessToken, renderModelManifestEntry, renderModelManifestFields, renderModelManifestList, requireCliContext, resolveActiveEnvName, resolveCliModel, resolveOutputConfig, revokeToken, runCli, runPaginatedList, sanitizeString, saveCliConfig, setCliContext, withCallModelArgs, withEnv, withMultiplePages, withOutput, wrapCommandHandler };
9956
+ export { CALL_MODEL_API_PATH, CliError, DEFAULT_CLI_OIDC_SCOPES, DEFAULT_CLI_REDIRECT_URI, DEFAULT_CLI_SECRET_PATTERNS, DEFAULT_MANIFEST_HELP_DATA_FORMAT, DEFAULT_MANIFEST_HELP_MODE, DEFAULT_MANIFEST_MODEL_COMMAND_NAME, DEFAULT_MODEL_DECODE_COMMAND_NAME, DEFAULT_MODEL_INFO_COMMAND_NAME, DUMP_MERGE_MODES, DUMP_OUTPUT_MODES, MAX_MODEL_ACCESS_MULTI_READ_KEYS, MODEL_WRITE_OIDC_SCOPES, MULTIPLE_PAGES_OUTPUT_MODES, PROMPT_CANCELLED_ERROR_CODE, STANDARD_GLOBAL_OPTION_NAMES, applyEnvVarOverrides, buildAuthorizationUrl, buildCliPaths, buildDumpFilePath, buildErrorOutput, buildManifestCommands, buildModelDecodeCommand, buildModelInfoCommand, buildOidcDiscoveryCandidates, callModelOverHttp, callPassthroughCommand, configureCliErrorMapper, configureCliSecretPatterns, configureOutputOptions, createAuthCommand, createAuthMiddleware, createCallModelCommand, createCli, createCliContext, createCliTokenCacheStore, createContextSlot, createDoctorCommand, createEnvCommand, createOutputCommand, createOutputMiddleware, decodeFirestoreModelKey, defaultDoctorChecks, detectDataHelpFormat, detectHelpMode, discoverOidcMetadata, dumpTimestamp, exchangeAuthorizationCode, expandModelKeys, fetchUserInfo, filterReadOnlyModelScopes, findCliEnvDefault, findCliModelManifestEntry, generateOAuthState, generatePkceMaterial, getCliContext, getCommand, getManyCommand, getModelOverHttp, getMultipleModelsOverHttp, getOutputOptions, isCliEnvConfigComplete, isTokenExpired, loadCliConfig, maskSecret, mergeCliConfig, mergeCliEnvWithDefault, mergeOutputConfig, openStreamingDump, outputError, outputResult, parseGetArgs, parseGetManyArgs, parsePastedRedirect, pickFields, promptLine, refreshAccessToken, renderDecodedKey, renderModelManifestEntry, renderModelManifestFields, renderModelManifestList, requireCliContext, resolveActiveEnvName, resolveCliModel, resolveOutputConfig, revokeToken, runCli, runPaginatedList, sanitizeString, saveCliConfig, setCliContext, withCallModelArgs, withEnv, withMultiplePages, withOutput, wrapCommandHandler };