@dereekb/dbx-cli 13.11.11 → 13.11.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dereekb/dbx-cli/manifest-extract",
3
- "version": "13.11.11",
3
+ "version": "13.11.13",
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.11",
3
+ "version": "13.11.13",
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.11",
28
- "@dereekb/firebase": "13.11.11",
29
- "@dereekb/nestjs": "13.11.11",
30
- "@dereekb/util": "13.11.11",
33
+ "@dereekb/date": "13.11.13",
34
+ "@dereekb/firebase": "13.11.13",
35
+ "@dereekb/nestjs": "13.11.13",
36
+ "@dereekb/util": "13.11.13",
31
37
  "arktype": "^2.2.0",
32
38
  "yargs": "^18.0.0"
33
39
  },
@@ -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`.
@@ -112,6 +112,22 @@ export interface CreateCliInput {
112
112
  * @internal Intended for use from `@dereekb/dbx-cli/test`. Not for production wiring.
113
113
  */
114
114
  readonly testCliContext?: CliContext;
115
+ /**
116
+ * Optional version string. When set, yargs registers `--version` / `-V` on the root parser
117
+ * returning this value. Defaults to omitted (no `--version` flag).
118
+ *
119
+ * Consumers typically pass their `package.json` version (read at build time, e.g. via a
120
+ * bundler `define` or a generated module).
121
+ */
122
+ readonly version?: string;
123
+ /**
124
+ * Optional shell-completion command name. When set, yargs registers
125
+ * `<cli> <completionCommandName>` (defaults to `completion`) that emits a bash/zsh script.
126
+ * Pass `false` to disable.
127
+ *
128
+ * @default 'completion'
129
+ */
130
+ readonly completionCommandName?: string | false;
115
131
  }
116
132
  /**
117
133
  * Top-level CLI builder.
@@ -2,12 +2,28 @@ import type { Arguments } from 'yargs';
2
2
  /**
3
3
  * Wraps a yargs command handler with the standard structured-error boilerplate:
4
4
  * any thrown error is converted to a `{ ok: false, ... }` envelope via {@link outputError}
5
- * and the process exits with code 1.
5
+ * and the process exits with the supplied code (default {@link CLI_EXIT_CODE_HANDLER} = 1).
6
6
  *
7
7
  * Lets command files drop the per-handler `try { ... } catch (e) { outputError(e); process.exit(1); }`
8
8
  * block while keeping the same observable behavior.
9
9
  *
10
10
  * @param handler - The inner command handler to invoke. May be sync or async.
11
+ * @param exitCode - Optional override for the exit code on failure (defaults to {@link CLI_EXIT_CODE_HANDLER}).
11
12
  * @returns An async handler that delegates to `handler` and converts thrown errors into the standard envelope.
12
13
  */
13
- export declare function wrapCommandHandler<T>(handler: (argv: Arguments<T>) => Promise<void> | void): (argv: Arguments<T>) => Promise<void>;
14
+ export declare function wrapCommandHandler<T>(handler: (argv: Arguments<T>) => Promise<void> | void, exitCode?: number): (argv: Arguments<T>) => Promise<void>;
15
+ /**
16
+ * Sync variant of {@link wrapCommandHandler} for handlers that never return a Promise.
17
+ *
18
+ * Yargs invokes the wrapped function synchronously when registered, so errors thrown by the
19
+ * inner handler (and by `process.exit` itself when stubbed in tests) propagate synchronously —
20
+ * which is what `parseSync()`-based tests assert against via `expect(() => ...).toThrow(...)`.
21
+ *
22
+ * Use this when the inner handler does not perform any I/O. For async handlers (HTTP calls,
23
+ * disk reads, prompts) keep using {@link wrapCommandHandler}.
24
+ *
25
+ * @param handler - The inner sync command handler.
26
+ * @param exitCode - Optional override for the exit code on failure.
27
+ * @returns A sync handler that converts thrown errors into the standard envelope.
28
+ */
29
+ export declare function wrapSyncCommandHandler<T>(handler: (argv: Arguments<T>) => void, exitCode?: number): (argv: Arguments<T>) => void;
@@ -4,3 +4,4 @@ export * from './handler';
4
4
  export * from './interactive';
5
5
  export * from './output';
6
6
  export * from './pagination';
7
+ export * from './stdin';
@@ -20,7 +20,23 @@ export interface CliOutputOptions {
20
20
  readonly dumpDir?: string;
21
21
  readonly pick?: string;
22
22
  readonly commandPath?: string[];
23
+ /**
24
+ * When true, the stdout JSON envelope is rendered with 2-space indent instead of compact.
25
+ * Driven by the global `--pretty` flag.
26
+ */
27
+ readonly pretty?: boolean;
23
28
  }
29
+ /**
30
+ * Standard exit code used when a CLI command handler throws.
31
+ *
32
+ * Used by {@link wrapCommandHandler} when no override is supplied.
33
+ */
34
+ export declare const CLI_EXIT_CODE_HANDLER = 1;
35
+ /**
36
+ * Exit code used when the auth middleware itself fails (no env, no token, expired refresh,
37
+ * etc.) — distinct from a handler error so scripts can disambiguate auth from logic failures.
38
+ */
39
+ export declare const CLI_EXIT_CODE_AUTH = 4;
24
40
  /**
25
41
  * Patterns that indicate a string may contain a secret token or credential.
26
42
  */
@@ -54,6 +70,51 @@ export declare function configureOutputOptions(options: CliOutputOptions): void;
54
70
  * @returns The active output options (empty object when never configured).
55
71
  */
56
72
  export declare function getOutputOptions(): CliOutputOptions;
73
+ /**
74
+ * Toggles the process-wide verbose flag. The HTTP layer (`call-model.client.ts`,
75
+ * `oidc.client.ts`) checks {@link isCliVerbose} before each request and emits a
76
+ * `[<method> <url>]` trace line to stderr when enabled.
77
+ *
78
+ * @param value - Whether verbose tracing is on.
79
+ */
80
+ export declare function setCliVerbose(value: boolean): void;
81
+ /**
82
+ * @returns Whether the verbose flag is currently enabled.
83
+ */
84
+ export declare function isCliVerbose(): boolean;
85
+ /**
86
+ * Writes a one-line stderr trace prefixed with `[verbose]` when the verbose
87
+ * flag is on. No-op otherwise. Kept off stdout so the JSON envelope on stdout
88
+ * stays parseable.
89
+ *
90
+ * @param message - The trace message.
91
+ */
92
+ export declare function verboseLog(message: string): void;
93
+ /**
94
+ * Drop-in `fetch` replacement that wraps the request with the configured verbose-trace
95
+ * and `--timeout` behavior. Aborts via `AbortController` after the configured timeout.
96
+ *
97
+ * Translates an aborted request into a {@link CliError} with code `TIMEOUT`.
98
+ *
99
+ * @param fetcher - The underlying fetch impl (defaults to global `fetch`). Allows tests to inject.
100
+ * @param input - The first arg to fetch (URL or Request).
101
+ * @param init - The RequestInit. Any existing `signal` is preserved; we only attach our own when no signal was supplied.
102
+ * @returns The fetch Response.
103
+ */
104
+ export declare function tracedFetch(fetcher: typeof fetch | undefined, input: string | URL | Request, init?: RequestInit): Promise<Response>;
105
+ /**
106
+ * Sets the process-wide HTTP timeout (in milliseconds) honored by the HTTP layer.
107
+ *
108
+ * Pass `undefined` to clear. The HTTP helpers thread this into an `AbortController`
109
+ * so individual `fetch` calls cancel after the configured duration.
110
+ *
111
+ * @param ms - Timeout in ms, or `undefined` to clear.
112
+ */
113
+ export declare function setCliTimeoutMs(ms: Maybe<number>): void;
114
+ /**
115
+ * @returns The current process-wide HTTP timeout in ms, or `undefined` when unset.
116
+ */
117
+ export declare function getCliTimeoutMs(): Maybe<number>;
57
118
  /**
58
119
  * Replaces the active secret-redaction pattern list with the given patterns.
59
120
  *
@@ -110,7 +171,8 @@ export declare function pickFields<T>(data: T, pick: string): T;
110
171
  * Prints a successful command result as a `{ ok: true, data, meta? }` JSON envelope on stdout.
111
172
  *
112
173
  * Also writes a full unfiltered dump to disk when `dumpDir` is configured, then applies any
113
- * configured `pick` filter to the stdout payload.
174
+ * configured `pick` filter to the stdout payload. Honors the global `--pretty` flag for the
175
+ * stdout payload only (the dump-to-disk path is always pretty-printed).
114
176
  *
115
177
  * @param data - The command result to emit.
116
178
  * @param meta - Optional additional metadata to attach to the envelope.
@@ -119,6 +181,8 @@ export declare function outputResult<T>(data: T, meta?: Record<string, unknown>)
119
181
  /**
120
182
  * Prints a failed command result as a `{ ok: false, error, code, suggestion? }` JSON envelope on stdout.
121
183
  *
184
+ * Honors the global `--pretty` flag.
185
+ *
122
186
  * @param error - The thrown value to convert. Mapped via {@link buildErrorOutput} (which consults any registered {@link CliErrorMapper}).
123
187
  */
124
188
  export declare function outputError(error: unknown): void;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Returns `true` when the user passed `-` (the conventional "read from stdin" sentinel) as a
3
+ * positional or flag value. Centralizes the convention so command handlers can pattern-match
4
+ * consistently.
5
+ *
6
+ * @param value - The raw argv value to inspect.
7
+ * @returns `true` when the value is exactly `'-'`.
8
+ * @__NO_SIDE_EFFECTS__
9
+ */
10
+ export declare function isStdinSentinel(value: unknown): boolean;
11
+ /**
12
+ * Reads the entire contents of `process.stdin` as a UTF-8 string.
13
+ *
14
+ * Used by command handlers that accept `-` to mean "read from stdin" (e.g. `--data -`,
15
+ * `get-many -`). Resolves once the stream emits `end`; no timeout is applied — callers that
16
+ * need one should wrap with `Promise.race`.
17
+ *
18
+ * @returns The UTF-8 decoded stdin contents.
19
+ */
20
+ export declare function readAllStdin(): Promise<string>;
21
+ /**
22
+ * Reads stdin as a list of whitespace-separated tokens (newlines, spaces, tabs).
23
+ *
24
+ * Empty tokens are dropped so a trailing newline doesn't introduce a phantom entry.
25
+ *
26
+ * @returns The tokens parsed from stdin.
27
+ */
28
+ export declare function readStdinTokens(): Promise<string[]>;
@@ -0,0 +1 @@
1
+ exports._default = require('./index.cjs.js').default;