@dereekb/dbx-cli 13.11.10 → 13.11.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,6 @@
2
2
 
3
3
  var tsMorph = require('ts-morph');
4
4
 
5
- // 'query' is accepted today even though `<Group>ModelCrudFunctionsConfig` in @dereekb/firebase does not yet permit `query:` keys (deferred follow-up). Once query support lands upstream, every query entry flows through here with no change.
6
5
  var SUPPORTED_VERBS = new Set([
7
6
  'create',
8
7
  'read',
@@ -1,6 +1,5 @@
1
1
  import { Project, Node } from 'ts-morph';
2
2
 
3
- // 'query' is accepted today even though `<Group>ModelCrudFunctionsConfig` in @dereekb/firebase does not yet permit `query:` keys (deferred follow-up). Once query support lands upstream, every query entry flows through here with no change.
4
3
  var SUPPORTED_VERBS = new Set([
5
4
  'create',
6
5
  'read',
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dereekb/dbx-cli/manifest-extract",
3
- "version": "13.11.10",
3
+ "version": "13.11.12",
4
4
  "sideEffects": false,
5
5
  "peerDependencies": {
6
6
  "ts-morph": "^21.0.0"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dereekb/dbx-cli",
3
- "version": "13.11.10",
3
+ "version": "13.11.12",
4
4
  "sideEffects": false,
5
5
  "bin": {
6
6
  "dbx-cli-generate-firebase-api-manifest": "firebase-api-manifest/main.js"
@@ -15,6 +15,12 @@
15
15
  "import": "./manifest-extract/index.cjs.mjs",
16
16
  "default": "./manifest-extract/index.cjs.js"
17
17
  },
18
+ "./test": {
19
+ "module": "./test/index.esm.js",
20
+ "types": "./test/index.d.ts",
21
+ "import": "./test/index.cjs.mjs",
22
+ "default": "./test/index.cjs.js"
23
+ },
18
24
  "./package.json": "./package.json",
19
25
  ".": {
20
26
  "module": "./index.esm.js",
@@ -24,10 +30,10 @@
24
30
  }
25
31
  },
26
32
  "peerDependencies": {
27
- "@dereekb/date": "13.11.10",
28
- "@dereekb/firebase": "13.11.10",
29
- "@dereekb/nestjs": "13.11.10",
30
- "@dereekb/util": "13.11.10",
33
+ "@dereekb/date": "13.11.12",
34
+ "@dereekb/firebase": "13.11.12",
35
+ "@dereekb/nestjs": "13.11.12",
36
+ "@dereekb/util": "13.11.12",
31
37
  "arktype": "^2.2.0",
32
38
  "yargs": "^18.0.0"
33
39
  },
@@ -0,0 +1,80 @@
1
+ import type { Argv, CommandModule } from 'yargs';
2
+ import { type CliContext } from '../context/cli.context';
3
+ /**
4
+ * Specification for a composite action command surfaced under `<cli> action ...`.
5
+ *
6
+ * Actions are user-defined async lambdas that chain multiple {@link CliContext.callModel} /
7
+ * {@link CliContext.getModel} / {@link CliContext.getMultipleModels} calls in-process,
8
+ * letting consumers expose high-leverage workflows (paginate-and-aggregate, fan-out,
9
+ * derived projections) without spending a CLI round-trip per call.
10
+ *
11
+ * Each action runs after the standard auth middleware, so the {@link CliContext} is
12
+ * already populated by the time {@link ActionCommandSpec.handler} fires.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * const districtsForRegion: ActionCommandSpec = {
17
+ * command: 'districts <region>',
18
+ * describe: 'List every District in a Region.',
19
+ * model: 'region',
20
+ * builder: (y) => y.positional('region', { type: 'string' }),
21
+ * handler: async ({ context, argv }) => {
22
+ * const region = String(argv.region);
23
+ * return context.callModel({ modelType: 'district', call: 'query', data: { region } });
24
+ * }
25
+ * };
26
+ * ```
27
+ */
28
+ export interface ActionCommandSpec<TArgv = any, TResult = unknown> {
29
+ /**
30
+ * Yargs command string for the action's leaf — positionals come after the action name.
31
+ * Example: `'open-jobs-for-region <region>'` resolves to `<cli> action open-jobs-for-region <region>`
32
+ * (or `<cli> action <model> open-jobs-for-region <region>` when {@link model} is set).
33
+ */
34
+ readonly command: string;
35
+ /**
36
+ * Short one-line description shown in `<cli> action --help`.
37
+ */
38
+ readonly describe: string;
39
+ /**
40
+ * When provided, the action is grouped under `<cli> action <model> <action>` instead of
41
+ * the root `<cli> action <action>`. Use the model's persisted type (e.g. `'region'`,
42
+ * `'district'`) so the grouping mirrors `model <model>` from {@link buildManifestCommands}.
43
+ */
44
+ readonly model?: string;
45
+ /**
46
+ * Optional yargs builder. Use to declare positionals and options that the action consumes.
47
+ */
48
+ readonly builder?: (yargs: Argv) => Argv;
49
+ /**
50
+ * Optional epilogue rendered after `--help` for this action.
51
+ */
52
+ readonly helpEpilogue?: string;
53
+ /**
54
+ * The action body. Receives the live {@link CliContext} (auth already resolved) and the
55
+ * parsed argv. Throwing a {@link CliError} surfaces a structured failure envelope.
56
+ */
57
+ readonly handler: (input: {
58
+ readonly context: CliContext;
59
+ readonly argv: TArgv;
60
+ }) => Promise<TResult> | TResult;
61
+ /**
62
+ * Optional result transform applied before {@link outputResult} serialises the value.
63
+ * Use to strip noise (e.g. paging cursors) or shape the response for downstream callers.
64
+ */
65
+ readonly mapResult?: (result: TResult) => unknown;
66
+ }
67
+ /**
68
+ * Wraps an {@link ActionCommandSpec} as a yargs `CommandModule`.
69
+ *
70
+ * The returned command:
71
+ * - Calls {@link requireCliContext} so it fails loudly when auth middleware did not run.
72
+ * - Invokes `spec.handler({ context, argv })`.
73
+ * - Pipes the result through `spec.mapResult` when provided.
74
+ * - Emits the value via {@link outputResult}; emits {@link outputError} + `process.exit(1)` on failure.
75
+ *
76
+ * @param spec - The action specification.
77
+ * @returns The yargs command module ready to be registered under the `action` parent.
78
+ * @__NO_SIDE_EFFECTS__
79
+ */
80
+ export declare function createActionCommand<TArgv = any, TResult = unknown>(spec: ActionCommandSpec<TArgv, TResult>): CommandModule;
@@ -0,0 +1,30 @@
1
+ import type { CommandModule } from 'yargs';
2
+ import { type ActionCommandSpec } from './action.command.factory';
3
+ /**
4
+ * Default name of the parent command that groups all registered action specs.
5
+ * Surfaces as `<cli> action <action>` (root) and `<cli> action <model> <action>` (model-scoped).
6
+ */
7
+ export declare const DEFAULT_ACTION_COMMAND_NAME = "action";
8
+ /**
9
+ * Options accepted by {@link buildActionCommands}.
10
+ */
11
+ export interface BuildActionCommandsOptions {
12
+ /**
13
+ * Name of the parent command that groups all action specs. Defaults to
14
+ * {@link DEFAULT_ACTION_COMMAND_NAME} (`action`).
15
+ */
16
+ readonly actionCommandName?: string;
17
+ }
18
+ /**
19
+ * Assembles the parent `action` command tree from a list of {@link ActionCommandSpec}s.
20
+ *
21
+ * Specs without a `model` are appended as direct subcommands of `action`. Specs with a
22
+ * `model` are grouped under `action <model> <action>` (mirroring `buildManifestCommands`'
23
+ * `model <model> <action>` shape) so the model-scoped surface stays browseable.
24
+ *
25
+ * @param specs - The action specs registered by the app.
26
+ * @param options - Optional overrides (e.g. parent command name).
27
+ * @returns An array containing a single parent `action` command, or empty when no specs were provided.
28
+ * @__NO_SIDE_EFFECTS__
29
+ */
30
+ export declare function buildActionCommands(specs: readonly ActionCommandSpec[], options?: BuildActionCommandsOptions): CommandModule[];
@@ -0,0 +1,3 @@
1
+ export * from './action.command.factory';
2
+ export * from './build-action-commands';
3
+ export * from './iterate';
@@ -0,0 +1,231 @@
1
+ import type { OnCallFunctionType, OnCallQueryModelResult } from '@dereekb/firebase';
2
+ import { type Maybe, type PerformAsyncTasksConfig } from '@dereekb/util';
3
+ import { type CliContext } from '../context/cli.context';
4
+ /**
5
+ * State passed into {@link IterateDbxCliCallModelConfig.buildRequestData} when assembling
6
+ * the next page's request payload.
7
+ */
8
+ export interface IterateDbxCliCallModelPageState {
9
+ /**
10
+ * Zero-based index of the page about to be fetched.
11
+ */
12
+ readonly pageIndex: number;
13
+ /**
14
+ * Cursor key returned by the previous page, or undefined for the first page.
15
+ */
16
+ readonly cursorDocumentKey: Maybe<string>;
17
+ /**
18
+ * Total items visited prior to this page.
19
+ */
20
+ readonly visitedItems: number;
21
+ }
22
+ /**
23
+ * Per-item callback signature for {@link iterateDbxCliCallModel}.
24
+ *
25
+ * @typeParam TItem - The item type yielded by the page response.
26
+ * @typeParam TItemResult - The value produced by processing one item.
27
+ */
28
+ export type IterateDbxCliCallModelItemFn<TItem, TItemResult> = (input: {
29
+ readonly context: CliContext;
30
+ readonly item: TItem;
31
+ readonly key: string;
32
+ readonly pageIndex: number;
33
+ readonly itemIndex: number;
34
+ }) => Promise<TItemResult>;
35
+ /**
36
+ * Per-page callback signature for {@link iterateDbxCliCallModel}. Invoked after
37
+ * {@link IterateDbxCliCallModelItemFn} (when both are configured).
38
+ */
39
+ export type IterateDbxCliCallModelPageFn<TItem, TRaw, TItemResult, TPageResult> = (input: {
40
+ readonly context: CliContext;
41
+ readonly page: TRaw;
42
+ readonly items: ReadonlyArray<TItem>;
43
+ readonly keys: ReadonlyArray<string>;
44
+ readonly pageIndex: number;
45
+ readonly pageItemResults?: ReadonlyArray<TItemResult>;
46
+ }) => Promise<TPageResult>;
47
+ /**
48
+ * Adapter that maps an arbitrary `callModel` response shape into the pieces
49
+ * {@link iterateDbxCliCallModel} needs (items, cursor, has-more).
50
+ *
51
+ * Defaults to the {@link OnCallQueryModelResult} shape — supply a custom adapter
52
+ * when iterating responses from other call types (e.g. `getMultiple`-style calls
53
+ * or custom standalone calls that return an array of records).
54
+ */
55
+ export interface IterateDbxCliCallModelResponseAdapter<TRaw, TItem> {
56
+ /**
57
+ * Pulls the page's items out of the raw response.
58
+ */
59
+ readonly items: (raw: TRaw) => ReadonlyArray<TItem>;
60
+ /**
61
+ * Returns the keys aligned with {@link items}. Defaults to an empty array when omitted.
62
+ */
63
+ readonly keys?: (raw: TRaw) => ReadonlyArray<string>;
64
+ /**
65
+ * Returns the cursor key for the next page, or undefined to stop.
66
+ */
67
+ readonly cursorDocumentKey?: (raw: TRaw) => Maybe<string>;
68
+ /**
69
+ * Overrides the "keep going" check. Defaults to `!!cursorDocumentKey(raw)`.
70
+ */
71
+ readonly hasMore?: (raw: TRaw) => boolean;
72
+ }
73
+ /**
74
+ * Config for {@link iterateDbxCliCallModel}.
75
+ *
76
+ * Cursor-paginated iterator over a `callModel` endpoint that returns an array of
77
+ * items. The default {@link responseAdapter} reads {@link OnCallQueryModelResult}
78
+ * fields (`results`, `keys`, `cursorDocumentKey`, `hasMore`), so a typical
79
+ * `call: 'query'` flow only needs to specify `modelType` and `params`. Custom
80
+ * call shapes can override both {@link buildRequestData} and {@link responseAdapter}.
81
+ *
82
+ * @typeParam TParams - The request data shape passed to `callModel`.
83
+ * @typeParam TItem - The item type yielded by the page response.
84
+ * @typeParam TRaw - The full raw response shape. Defaults to {@link OnCallQueryModelResult}<TItem>.
85
+ * @typeParam TItemResult - Per-item processing result type.
86
+ * @typeParam TPageResult - Per-page processing result type.
87
+ */
88
+ export interface IterateDbxCliCallModelConfig<TParams, TItem, TRaw = OnCallQueryModelResult<TItem>, TItemResult = void, TPageResult = void> {
89
+ /**
90
+ * Active CLI context (provides callModel + auth).
91
+ */
92
+ readonly context: CliContext;
93
+ /**
94
+ * Target model type, e.g. `'guestbook'`.
95
+ */
96
+ readonly modelType: string;
97
+ /**
98
+ * Call type.
99
+ */
100
+ readonly call: OnCallFunctionType;
101
+ /**
102
+ * Optional specifier passed through to `OnCallTypedModelParams`.
103
+ */
104
+ readonly specifier?: string;
105
+ /**
106
+ * Base request data merged into each page request. The iterator owns the
107
+ * `cursorDocumentKey` field — anything else on the object (filters, parent
108
+ * keys, etc.) is forwarded verbatim.
109
+ */
110
+ readonly params: TParams;
111
+ /**
112
+ * Override how the per-page request data is assembled. Defaults to spreading
113
+ * `params` with `cursorDocumentKey` and (when {@link limitPerPage} or the
114
+ * remaining {@link totalItemsLimit} budget is set) `limit` injected.
115
+ */
116
+ readonly buildRequestData?: (params: TParams, state: IterateDbxCliCallModelPageState, limit: Maybe<number>) => TParams;
117
+ /**
118
+ * Adapter for non-{@link OnCallQueryModelResult} responses.
119
+ */
120
+ readonly responseAdapter?: IterateDbxCliCallModelResponseAdapter<TRaw, TItem>;
121
+ /**
122
+ * Per-page request limit. Forwarded into the default {@link buildRequestData}.
123
+ */
124
+ readonly limitPerPage?: number;
125
+ /**
126
+ * Stop once this many items have been visited across all pages.
127
+ */
128
+ readonly totalItemsLimit?: number;
129
+ /**
130
+ * Stop after this many pages.
131
+ */
132
+ readonly maxPages?: number;
133
+ /**
134
+ * Per-item processing callback. Parallelism controlled by {@link maxParallelPerPage}.
135
+ */
136
+ readonly iterateItem?: IterateDbxCliCallModelItemFn<TItem, TItemResult>;
137
+ /**
138
+ * Per-page processing callback. Runs after {@link iterateItem} when both are set.
139
+ */
140
+ readonly iteratePage?: IterateDbxCliCallModelPageFn<TItem, TRaw, TItemResult, TPageResult>;
141
+ /**
142
+ * Concurrency knobs forwarded to `performAsyncTasks` for {@link iterateItem}.
143
+ */
144
+ readonly itemPerformTasksConfig?: Partial<PerformAsyncTasksConfig<TItem>>;
145
+ /**
146
+ * Shorthand for `itemPerformTasksConfig.maxParallelTasks`.
147
+ */
148
+ readonly maxParallelPerPage?: number;
149
+ /**
150
+ * Collect items into the result array. Defaults to true.
151
+ */
152
+ readonly collectItems?: boolean;
153
+ /**
154
+ * Collect per-item results into the result array. Defaults to true when {@link iterateItem} is set.
155
+ */
156
+ readonly collectItemResults?: boolean;
157
+ /**
158
+ * Collect per-page results into the result array. Defaults to true when {@link iteratePage} is set.
159
+ */
160
+ readonly collectPageResults?: boolean;
161
+ }
162
+ /**
163
+ * Aggregate result returned by {@link iterateDbxCliCallModel}.
164
+ */
165
+ export interface IterateDbxCliCallModelResult<TItem, TItemResult, TPageResult> {
166
+ /**
167
+ * Number of pages fetched.
168
+ */
169
+ readonly totalPages: number;
170
+ /**
171
+ * Number of items visited across all pages.
172
+ */
173
+ readonly totalItems: number;
174
+ /**
175
+ * True when iteration stopped because of `totalItemsLimit` / `maxPages`.
176
+ */
177
+ readonly hitLimit: boolean;
178
+ /**
179
+ * Last cursor seen. Useful for callers that want to resume later.
180
+ */
181
+ readonly lastCursorDocumentKey: Maybe<string>;
182
+ /**
183
+ * Flat list of items across all pages. Present when `collectItems !== false`.
184
+ */
185
+ readonly items?: ReadonlyArray<TItem>;
186
+ /**
187
+ * Flat list of per-item processing results. Present when {@link iterateItem} ran and `collectItemResults !== false`.
188
+ */
189
+ readonly itemResults?: ReadonlyArray<TItemResult>;
190
+ /**
191
+ * Per-page processing results. Present when {@link iteratePage} ran and `collectPageResults !== false`.
192
+ */
193
+ readonly pageResults?: ReadonlyArray<TPageResult>;
194
+ }
195
+ /**
196
+ * Iterates a paginated `callModel` endpoint, exhausting (or stopping at the configured limit) all pages.
197
+ *
198
+ * Cursor-paginated analog of {@link iterateFirestoreDocumentSnapshots}, but speaking HTTP/`callModel`
199
+ * rather than direct Firestore. The default response adapter reads the canonical
200
+ * {@link OnCallQueryModelResult} shape — supply a custom adapter to iterate other array-returning
201
+ * call types (e.g. a `getMultiple`-style standalone call).
202
+ *
203
+ * Concurrency: pages are fetched serially (cursor dependency); items within a page can run
204
+ * in parallel via `maxParallelPerPage` (forwarded to `performAsyncTasks`).
205
+ *
206
+ * @example
207
+ * ```ts
208
+ * // Exhaust every published Guestbook entry for a single Guestbook.
209
+ * const { totalItems, items } = await iterateDbxCliCallModel<QueryGuestbookEntriesParams, GuestbookEntry>({
210
+ * context,
211
+ * modelType: 'guestbookEntry',
212
+ * params: { guestbook: 'gb/abc', published: true }
213
+ * });
214
+ * ```
215
+ *
216
+ * @example
217
+ * ```ts
218
+ * // Fan out to a child action per Guestbook, with 4-way parallelism per page.
219
+ * const { itemResults } = await iterateDbxCliCallModel<QueryGuestbooksParams, Guestbook, OnCallQueryModelResult<Guestbook>, EntriesForGuestbook>({
220
+ * context,
221
+ * modelType: 'guestbook',
222
+ * params: { published: true },
223
+ * maxParallelPerPage: 4,
224
+ * iterateItem: ({ context, key }) => queryGuestbookEntriesForGuestbook({ context, guestbook: key, published: true })
225
+ * });
226
+ * ```
227
+ *
228
+ * @param config - Iterator configuration.
229
+ * @returns The aggregate result.
230
+ */
231
+ export declare function iterateDbxCliCallModel<TParams, TItem, TRaw = OnCallQueryModelResult<TItem>, TItemResult = void, TPageResult = void>(config: IterateDbxCliCallModelConfig<TParams, TItem, TRaw, TItemResult, TPageResult>): Promise<IterateDbxCliCallModelResult<TItem, TItemResult, TPageResult>>;
@@ -28,10 +28,6 @@ export interface CallModelOverHttpResponse<R = unknown> {
28
28
  * The function name is referenced via {@link CALL_MODEL_APP_FUNCTION_KEY} for consistency with the demo's wiring.
29
29
  *
30
30
  * @param input - The call envelope describing the API target, access token, model params, and optional fetch override.
31
- * @param input.apiBaseUrl - The API base URL (the `/model/call` path is appended automatically).
32
- * @param input.accessToken - The Bearer access token sent in the `Authorization` header.
33
- * @param input.params - The {@link OnCallTypedModelParams} payload posted as JSON.
34
- * @param input.fetcher - Optional fetch implementation override (used by tests).
35
31
  * @returns The parsed JSON response body cast to `R`.
36
32
  */
37
33
  export declare function callModelOverHttp<T = unknown, R = unknown>(input: CallModelOverHttpInput<T>): Promise<R>;
@@ -105,8 +101,20 @@ export interface GetMultipleModelsOverHttpResult<T = unknown> {
105
101
  *
106
102
  * Backend route: `ModelApiController.getMany` (packages/firebase-server). Same `'read'` role enforcement.
107
103
  *
104
+ * For >50 keys, use {@link getMultipleModelsOverHttpChunked} to auto-batch and merge.
105
+ *
108
106
  * @param input - The request envelope describing the API target, access token, model, keys, and optional fetch override.
109
107
  * @returns The parsed `{ results, errors }` envelope.
110
108
  */
111
109
  export declare function getMultipleModelsOverHttp<T = unknown>(input: GetMultipleModelsOverHttpInput): Promise<GetMultipleModelsOverHttpResult<T>>;
110
+ /**
111
+ * Batch-reads any number of keys by chunking into requests of {@link MAX_MODEL_ACCESS_MULTI_READ_KEYS}
112
+ * keys each and merging the `{ results, errors }` envelopes across batches.
113
+ *
114
+ * Chunks are sent sequentially so a single env doesn't see a burst of concurrent connections.
115
+ *
116
+ * @param input - Same shape as {@link GetMultipleModelsOverHttpInput} but without the 50-key cap.
117
+ * @returns The merged `{ results, errors }` envelope across all chunks.
118
+ */
119
+ export declare function getMultipleModelsOverHttpChunked<T = unknown>(input: GetMultipleModelsOverHttpInput): Promise<GetMultipleModelsOverHttpResult<T>>;
112
120
  export { CALL_MODEL_APP_FUNCTION_KEY } from '@dereekb/firebase';
@@ -2,9 +2,13 @@ import type { CommandModule } from 'yargs';
2
2
  /**
3
3
  * Top-level `get-many <firstArg> [rest..]` command.
4
4
  *
5
- * Batch-reads up to 50 Firestore documents in a single request. The first positional can either
6
- * be an explicit modelType (followed by ≥1 keys) or a full key (followed by additional keys whose
7
- * prefixes must resolve to the same modelType).
5
+ * Batch-reads Firestore documents by key. The first positional can either be an explicit
6
+ * modelType (followed by ≥1 keys) or a full key (followed by additional keys whose prefixes
7
+ * must resolve to the same modelType). Beyond 50 keys the request is automatically chunked
8
+ * via `context.getMultipleModels`.
9
+ *
10
+ * Stdin: pass `-` as the only positional to read whitespace-separated keys from stdin
11
+ * (e.g. `cat keys.txt | <cli> get-many -`).
8
12
  *
9
13
  * Backend: `POST <apiBaseUrl>/model/<modelType>/get` with body `{ keys }` (ModelApiController.getMany).
10
14
  */
@@ -1,5 +1,17 @@
1
1
  import { type Maybe } from '@dereekb/util';
2
2
  import { type CliEnvConfig } from './env';
3
+ /**
4
+ * Returns a copy of the env config with the OAuth client id and secret masked via
5
+ * {@link maskSecret}. The remaining URLs/scopes pass through untouched.
6
+ *
7
+ * Used by every command that surfaces an env to the user (`auth status`, `auth show`,
8
+ * `env list`, `env show`, …) so secrets never end up in the JSON envelope.
9
+ *
10
+ * @param env - The env config to mask.
11
+ * @returns A plain object suitable for the structured stdout envelope.
12
+ * @__NO_SIDE_EFFECTS__
13
+ */
14
+ export declare function maskEnv(env: CliEnvConfig): Record<string, unknown>;
3
15
  /**
4
16
  * Output settings that can be applied per-command.
5
17
  */
@@ -0,0 +1,98 @@
1
+ import { type Maybe } from '@dereekb/util';
2
+ import { type CliConfig } from './cli.config';
3
+ import { type CliEnvConfig, type CliEnvDefault } from './env';
4
+ import { type CliPaths } from './paths';
5
+ /**
6
+ * The narrowed env shape returned by {@link resolveCliEnvOrThrow} when `requireComplete: true`.
7
+ *
8
+ * Guarantees that the OIDC client fields are present so callers can pass them through to the
9
+ * OIDC client/token helpers without a non-null assertion or extra runtime check.
10
+ */
11
+ export type CliEnvConfigComplete = Required<Pick<CliEnvConfig, 'apiBaseUrl' | 'oidcIssuer' | 'clientId' | 'clientSecret' | 'redirectUri'>> & CliEnvConfig;
12
+ /**
13
+ * Builds the conventional `<CLINAME>_ENV` env var name from the CLI binary name.
14
+ *
15
+ * Example: `demo-cli` → `DEMO_CLI_ENV`.
16
+ *
17
+ * @param cliName - The CLI's binary name (typically a kebab-case slug).
18
+ * @returns The uppercased, underscored env var name used to override the active env.
19
+ * @__NO_SIDE_EFFECTS__
20
+ */
21
+ export declare function getCliEnvVarName(cliName: string): string;
22
+ export interface ResolveCliEnvInput {
23
+ readonly cliName: string;
24
+ readonly paths: CliPaths;
25
+ /**
26
+ * Value passed via `--env <name>` (highest priority).
27
+ */
28
+ readonly flagEnv?: Maybe<string>;
29
+ /**
30
+ * Optional override for the env-name env var. Defaults to {@link getCliEnvVarName}(cliName).
31
+ */
32
+ readonly envVarName?: string;
33
+ /**
34
+ * Optional built-in env presets merged underneath the user's stored env when names match.
35
+ */
36
+ readonly defaultEnvs?: readonly CliEnvDefault[];
37
+ }
38
+ export interface ResolveCliEnvResult {
39
+ /**
40
+ * The loaded persisted CLI config (possibly empty when no config has been saved yet).
41
+ */
42
+ readonly config: CliConfig;
43
+ /**
44
+ * The resolved active env name from flag/env-var/active default, or `undefined` when none.
45
+ */
46
+ readonly envName: Maybe<string>;
47
+ /**
48
+ * The merged env config (stored env + default + env-var overrides), or `undefined` when
49
+ * neither the stored env nor any defaults/overrides cover this name.
50
+ */
51
+ readonly env: Maybe<CliEnvConfig>;
52
+ }
53
+ /**
54
+ * Resolves the active env for a CLI invocation in one call.
55
+ *
56
+ * Performs the env-resolution dance that every per-env command needs:
57
+ * 1. Load `<configDir>/config.json` (may be missing — returns `{}` in that case).
58
+ * 2. Resolve env name: `flagEnv` → `process.env[<CLINAME>_ENV]` → `config.activeEnv`.
59
+ * 3. Look up the stored env block (may be missing).
60
+ * 4. Merge with the matching {@link CliEnvDefault} (when one is registered).
61
+ * 5. Overlay `<CLINAME>_*` env var overrides.
62
+ *
63
+ * Non-throwing: returns `{ env: undefined, envName: undefined }` when the user has not
64
+ * configured anything. Use {@link resolveCliEnvOrThrow} for the "command requires an env"
65
+ * variant.
66
+ *
67
+ * @param input - Resolution inputs.
68
+ * @returns The resolved env triple.
69
+ */
70
+ export declare function resolveCliEnv(input: ResolveCliEnvInput): Promise<ResolveCliEnvResult>;
71
+ export interface ResolveCliEnvOrThrowInput extends ResolveCliEnvInput {
72
+ /**
73
+ * When `true`, throws `AUTH_ENV_INCOMPLETE` if the resolved env is missing OIDC fields
74
+ * (apiBaseUrl, oidcIssuer, clientId, clientSecret, redirectUri). The returned env is narrowed
75
+ * to {@link CliEnvConfigComplete}. Defaults to `false`.
76
+ */
77
+ readonly requireComplete?: boolean;
78
+ }
79
+ export interface ResolveCliEnvOrThrowResult<E extends CliEnvConfig = CliEnvConfig> {
80
+ readonly config: CliConfig;
81
+ readonly envName: string;
82
+ readonly env: E;
83
+ }
84
+ /**
85
+ * Throwing variant of {@link resolveCliEnv}.
86
+ *
87
+ * - Throws `NO_ACTIVE_ENV` when neither `--env`, the env var, nor `activeEnv` resolves.
88
+ * - Throws `ENV_NOT_FOUND` when the resolved name has no stored config and no matching default.
89
+ * - Throws `AUTH_ENV_INCOMPLETE` when `requireComplete` is set and OIDC fields are missing.
90
+ *
91
+ * @param input - Resolution inputs (with optional `requireComplete`).
92
+ * @returns The resolved env triple with `envName` and `env` guaranteed present. When
93
+ * `requireComplete` is `true`, `env` is narrowed to {@link CliEnvConfigComplete}.
94
+ */
95
+ export declare function resolveCliEnvOrThrow(input: ResolveCliEnvOrThrowInput & {
96
+ readonly requireComplete: true;
97
+ }): Promise<ResolveCliEnvOrThrowResult<CliEnvConfigComplete>>;
98
+ export declare function resolveCliEnvOrThrow(input: ResolveCliEnvOrThrowInput): Promise<ResolveCliEnvOrThrowResult>;
@@ -1,4 +1,5 @@
1
1
  export * from './cli.config';
2
2
  export * from './env';
3
+ export * from './env.resolve';
3
4
  export * from './paths';
4
5
  export * from './token.cache';
@@ -9,7 +9,7 @@ import { type CliModelManifest } from '../manifest/types';
9
9
  * `<env.apiBaseUrl>/model/*`:
10
10
  * - {@link CliContext.callModel} → `POST /model/call` (typed model dispatch)
11
11
  * - {@link CliContext.getModel} → `GET /model/<modelType>/get?key=<key>`
12
- * - {@link CliContext.getMultipleModels} → `POST /model/<modelType>/get` with `{ keys }`
12
+ * - {@link CliContext.getMultipleModels} → `POST /model/<modelType>/get` with `{ keys }`, automatically chunked into batches of 50
13
13
  *
14
14
  * When provided by the runner, {@link CliContext.modelManifest} carries the generated
15
15
  * `CliModelManifest` so commands can resolve `prefix/id` keys to a `modelType`.
@@ -1,3 +1,4 @@
1
+ export * from './action';
1
2
  export * from './api';
2
3
  export * from './auth';
3
4
  export * from './config';
@@ -1,5 +1,6 @@
1
1
  import type { MiddlewareFunction } from 'yargs';
2
2
  import { type CliEnvDefault } from '../config/env';
3
+ import { type CliContext } from '../context/cli.context';
3
4
  import { type CliModelManifest } from '../manifest/types';
4
5
  export interface CreateAuthMiddlewareInput {
5
6
  readonly cliName: string;
@@ -34,3 +35,17 @@ export interface CreateAuthMiddlewareInput {
34
35
  * @__NO_SIDE_EFFECTS__
35
36
  */
36
37
  export declare function createAuthMiddleware(input: CreateAuthMiddlewareInput): MiddlewareFunction;
38
+ /**
39
+ * Test-only middleware that skips OIDC discovery, disk token loading, and token refresh, attaching
40
+ * a pre-built {@link CliContext} directly via {@link setCliContext}.
41
+ *
42
+ * @internal Intended for use by `@dereekb/dbx-cli/test`. Not for production wiring.
43
+ *
44
+ * @param input - The pre-built context to attach on every invocation.
45
+ * @param input.cliContext - The {@link CliContext} that will be attached via {@link setCliContext}.
46
+ * @returns A yargs middleware function that always sets the provided context.
47
+ * @__NO_SIDE_EFFECTS__
48
+ */
49
+ export declare function createPassthroughAuthMiddleware(input: {
50
+ readonly cliContext: CliContext;
51
+ }): MiddlewareFunction;