@dereekb/dbx-cli 13.38.0 → 13.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/eslint/package.json +8 -8
  2. package/firebase-api-manifest/package.json +3 -3
  3. package/firestore-query-manifest/main.js +3 -3
  4. package/firestore-query-manifest/package.json +3 -3
  5. package/generate-firestore-indexes/main.js +2 -2
  6. package/generate-firestore-indexes/package.json +2 -2
  7. package/generate-mcp-manifest/package.json +3 -3
  8. package/generate-route-manifest/package.json +2 -2
  9. package/index.esm.js +1011 -521
  10. package/lint-cache/package.json +2 -2
  11. package/manifest-extract/package.json +7 -7
  12. package/model-test/LICENSE +21 -0
  13. package/model-test/index.d.ts +1 -0
  14. package/model-test/index.esm.js +5984 -0
  15. package/model-test/package.json +21 -0
  16. package/model-test/src/index.d.ts +41 -0
  17. package/model-test/src/lib/fixture/archetype.d.ts +33 -0
  18. package/model-test/src/lib/fixture/extract.d.ts +37 -0
  19. package/model-test/src/lib/fixture/format.json.d.ts +24 -0
  20. package/model-test/src/lib/fixture/format.markdown.d.ts +23 -0
  21. package/model-test/src/lib/fixture/forward.d.ts +48 -0
  22. package/model-test/src/lib/fixture/framework-fixtures.d.ts +70 -0
  23. package/model-test/src/lib/fixture/inspect.d.ts +22 -0
  24. package/model-test/src/lib/fixture/scaffold.d.ts +74 -0
  25. package/model-test/src/lib/fixture/types.d.ts +175 -0
  26. package/model-test/src/lib/test/discover.d.ts +81 -0
  27. package/model-test/src/lib/test/extract.d.ts +49 -0
  28. package/model-test/src/lib/test/format.hotspots.d.ts +23 -0
  29. package/model-test/src/lib/test/format.json.d.ts +25 -0
  30. package/model-test/src/lib/test/format.list-app.d.ts +30 -0
  31. package/model-test/src/lib/test/format.markdown.d.ts +25 -0
  32. package/model-test/src/lib/test/hotspots.d.ts +98 -0
  33. package/model-test/src/lib/test/inspect.d.ts +32 -0
  34. package/model-test/src/lib/test/search.d.ts +34 -0
  35. package/model-test/src/lib/test/types.d.ts +179 -0
  36. package/package.json +18 -22
  37. package/route/package.json +12 -12
  38. package/src/lib/firestore/firestore.session.d.ts +40 -0
  39. package/src/lib/runner/index.d.ts +1 -0
  40. package/src/lib/runner/lifecycle.d.ts +85 -0
  41. package/src/lib/runner/run.d.ts +15 -1
  42. package/test/package.json +14 -14
  43. package/validate/LICENSE +21 -0
  44. package/validate/index.js +16641 -0
  45. package/validate/package.json +11 -0
  46. package/eslint/index.cjs.default.js +0 -1
  47. package/eslint/index.cjs.js +0 -1112
  48. package/eslint/index.cjs.mjs +0 -2
  49. package/index.cjs.js +0 -65624
  50. package/manifest-extract/index.cjs.default.js +0 -1
  51. package/manifest-extract/index.cjs.js +0 -1595
  52. package/manifest-extract/index.cjs.mjs +0 -2
  53. package/route/index.cjs.default.js +0 -1
  54. package/route/index.cjs.js +0 -18
  55. package/route/index.cjs.mjs +0 -2
  56. package/test/index.cjs.default.js +0 -1
  57. package/test/index.cjs.js +0 -383
  58. package/test/index.cjs.mjs +0 -2
@@ -49,6 +49,20 @@ export interface CreateCliFirestoreSessionContextInput {
49
49
  */
50
50
  readonly refreshSession?: boolean;
51
51
  }
52
+ /**
53
+ * The Firebase app name a direct-Firestore session registers for a CLI + env pair.
54
+ *
55
+ * Deriving the name rather than tracking apps in a side registry is what makes ONE app per CLI + env
56
+ * per process a property of the code instead of a convention: {@link createCliFirestoreSessionContext}
57
+ * looks this name up in `getApps()` before initializing, so repeated session opens in one process —
58
+ * a doctor probe alongside a command's own session, an action that re-resolves the accessor — all
59
+ * share a single app, and {@link closeAllCliFirebaseApps} finds it again from the name alone.
60
+ *
61
+ * @param input - The CLI name and env name the session targets.
62
+ * @returns The Firebase app name for that pair.
63
+ * @__NO_SIDE_EFFECTS__
64
+ */
65
+ export declare function cliFirebaseAppName(input: Pick<CreateCliFirestoreSessionContextInput, 'cliName' | 'envName'>): string;
52
66
  /**
53
67
  * Opens a direct Firestore connection as the authenticated CLI user.
54
68
  *
@@ -95,3 +109,29 @@ export declare function createCliFirestoreSessionContext(input: CreateCliFiresto
95
109
  * @param session - The session context to close.
96
110
  */
97
111
  export declare function closeCliFirestoreSessionContext(session: CliFirestoreSessionContext): Promise<void>;
112
+ /**
113
+ * Deletes every still-live Firebase app this CLI opened, whether or not a session was handed back.
114
+ *
115
+ * The CLI's last line of defence against a hang. `closeCliFirestoreSessionContext` covers the normal
116
+ * path, but it needs a session to be handed to it, and three cases never produce one:
117
+ *
118
+ * - a handshake that fails AFTER `initializeApp` — a rejected custom token, a failed App Check
119
+ * registration — throws, so the caller that catches it has an initialized app and no session;
120
+ * - a caller that opens its own session outside the context memo (the doctor probe) owns its own
121
+ * teardown, and forgetting it hangs the process;
122
+ * - a {@link CliContext} orphaned mid-invocation carries the only reference to its session memo.
123
+ *
124
+ * Each leaves an app whose `Firestore` and signed-in `Auth` hold the Node event loop open forever.
125
+ * `getApps()` already tracks every live app and `deleteApp` removes it from that list, so the app
126
+ * names {@link cliFirebaseAppName} derives are enough to find them again — no side registry to keep
127
+ * in sync, and idempotent by construction.
128
+ *
129
+ * Tolerant of failures for the same reason {@link closeCliFirestoreSessionContext} is: it runs after
130
+ * the result is already on stdout.
131
+ *
132
+ * @param input - The function inputs.
133
+ * @param input.cliName - The CLI whose apps should be closed. Apps belonging to other Firebase
134
+ * consumers in the same process are left alone.
135
+ * @returns Resolves once every matching app has been deleted.
136
+ */
137
+ export declare function closeAllCliFirebaseApps(input: Pick<CreateCliFirestoreSessionContextInput, 'cliName'>): Promise<void>;
@@ -1 +1,2 @@
1
+ export * from './lifecycle';
1
2
  export * from './run';
@@ -0,0 +1,85 @@
1
+ import { type Maybe, type PromiseOrValue } from '@dereekb/util';
2
+ import { type CliContext } from '../context/cli.context';
3
+ /**
4
+ * Input handed to a {@link CliSetupFunction} / {@link CliTeardownFunction}.
5
+ */
6
+ export interface CliLifecycleHookInput {
7
+ readonly cliName: string;
8
+ /**
9
+ * The invocation's {@link CliContext}, when one was built.
10
+ *
11
+ * Absent for an auth-bypassed command (`auth login`, `env list`, `firestore-queries`), and for a
12
+ * teardown that runs after authentication itself failed. A hook that needs the context should say
13
+ * so by throwing from `setup`, which aborts the command with an error envelope — a `teardown` must
14
+ * tolerate its absence, since it runs on paths `setup` never reached.
15
+ */
16
+ readonly context: Maybe<CliContext>;
17
+ }
18
+ /**
19
+ * App-supplied hook run once per invocation, after the command's arguments validate and the auth
20
+ * middleware has attached the {@link CliContext}, and before the command's handler.
21
+ *
22
+ * Runs inside the parser, so throwing aborts the command: the error is emitted as the standard error
23
+ * envelope and the process exits non-zero, with {@link CliTeardownFunction} still run. That makes it
24
+ * the right place for a precondition an app's commands all depend on.
25
+ */
26
+ export type CliSetupFunction = (input: CliLifecycleHookInput) => PromiseOrValue<void>;
27
+ /**
28
+ * App-supplied hook run once per invocation after the parser has fully settled, on both the success
29
+ * and the failure path, and BEFORE the CLI closes its direct-Firestore session — so the hook can
30
+ * still read Firestore through `input.context`.
31
+ *
32
+ * Best-effort, exactly like the built-in session teardown it precedes: it runs after the command's
33
+ * result is already on stdout, so a throw is swallowed (surfaced under `--verbose`) rather than
34
+ * changing what the caller sees or the exit code they get.
35
+ *
36
+ * A teardown may run when {@link CliSetupFunction} did NOT — an invocation that failed validation or
37
+ * authentication never reaches setup — so it must not assume setup's side effects are in place.
38
+ */
39
+ export type CliTeardownFunction = (input: CliLifecycleHookInput) => PromiseOrValue<void>;
40
+ /**
41
+ * The app-supplied lifecycle hooks accepted by `createCli` / `runCli`.
42
+ */
43
+ export interface CliLifecycleHooks {
44
+ /**
45
+ * Run once before the command's handler. See {@link CliSetupFunction}.
46
+ */
47
+ readonly setup?: Maybe<CliSetupFunction>;
48
+ /**
49
+ * Run once after the parser settles, before the direct-Firestore session is closed. See
50
+ * {@link CliTeardownFunction}.
51
+ */
52
+ readonly teardown?: Maybe<CliTeardownFunction>;
53
+ }
54
+ /**
55
+ * Input for {@link cliLifecycleRunner}.
56
+ */
57
+ export interface CliLifecycleRunnerInput extends CliLifecycleHooks {
58
+ readonly cliName: string;
59
+ }
60
+ /**
61
+ * The once-per-invocation view of an app's {@link CliLifecycleHooks}.
62
+ */
63
+ export interface CliLifecycleRunner {
64
+ /**
65
+ * Runs the app's `setup` hook, at most once, rethrowing whatever it throws.
66
+ */
67
+ readonly runSetup: (context: Maybe<CliContext>) => Promise<void>;
68
+ /**
69
+ * Runs the app's `teardown` hook, at most once, swallowing whatever it throws.
70
+ */
71
+ readonly runTeardown: (context: Maybe<CliContext>) => Promise<void>;
72
+ }
73
+ /**
74
+ * Wraps an app's lifecycle hooks so each runs at most once per process.
75
+ *
76
+ * The once-only guard is not a convenience: yargs re-runs a global middleware for every COMMAND
77
+ * LEVEL it parses, so a nested command (`action worker export`) enters the setup middleware three
78
+ * times. An app's `setup` is written as "prepare this invocation", not "prepare this command level",
79
+ * and a hook that opened a connection or wrote a file would do it three times over.
80
+ *
81
+ * @param input - The CLI name and the app's hooks.
82
+ * @returns The guarded runner.
83
+ * @__NO_SIDE_EFFECTS__
84
+ */
85
+ export declare function cliLifecycleRunner(input: CliLifecycleRunnerInput): CliLifecycleRunner;
@@ -5,6 +5,7 @@ import { type CliContext } from '../context/cli.context';
5
5
  import { type DoctorCheck } from '../doctor/doctor.command.factory';
6
6
  import { type CliFirestoreQueryManifest, type CliModelManifest } from '../manifest/types';
7
7
  import { type CliFirestoreBinding } from '../firestore/firestore.models';
8
+ import { type CliLifecycleHooks, type CliLifecycleRunner } from './lifecycle';
8
9
  /**
9
10
  * Names of the global options registered by {@link createCli} that are not
10
11
  * specific to a single manifest command's payload. Manifest commands hide
@@ -12,7 +13,7 @@ import { type CliFirestoreBinding } from '../firestore/firestore.models';
12
13
  * focuses on the schema sections.
13
14
  */
14
15
  export declare const STANDARD_GLOBAL_OPTION_NAMES: readonly string[];
15
- export interface CreateCliInput {
16
+ export interface CreateCliInput extends CliLifecycleHooks {
16
17
  readonly cliName: string;
17
18
  /**
18
19
  * App-specific config/utility commands appended after the built-in `auth`, `env`, and `doctor` commands.
@@ -145,6 +146,16 @@ export interface CreateCliInput {
145
146
  * bundler `define` or a generated module).
146
147
  */
147
148
  readonly version?: string;
149
+ /**
150
+ * The lifecycle runner guarding this invocation's {@link CliLifecycleHooks}.
151
+ *
152
+ * Passed by {@link runCli} so the setup hook the parser runs and the teardown hook the exit path
153
+ * runs share ONE guard — two runners built from the same hooks would each track their own
154
+ * "already ran" flag, and the pairing between them is the whole contract.
155
+ *
156
+ * @internal Apps pass `setup` / `teardown`, not this.
157
+ */
158
+ readonly lifecycle?: CliLifecycleRunner;
148
159
  /**
149
160
  * Optional shell-completion command name. When set, yargs registers
150
161
  * `<cli> <completionCommandName>` (defaults to `completion`) that emits a bash/zsh script.
@@ -177,6 +188,9 @@ export interface CreateCliInput {
177
188
  * if {@link CreateCliInput.modelManifest} is provided.
178
189
  * @param input.firestore - The app-supplied direct-Firestore binding; enables `firestore-get` / `firestore-query`.
179
190
  * @param input.firestoreQueryManifest - The generated Firestore query catalog; enables `firestore-queries`.
191
+ * @param input.setup - App hook run once before the command's handler; a throw aborts the command.
192
+ * @param input.teardown - App hook run once after the parser settles, before the Firestore session closes.
193
+ * Only {@link runCli} runs it — a caller that drives `createCli().parse()` itself owns its own teardown.
180
194
  * @returns The configured yargs `Argv` ready to be `.parse()`-d.
181
195
  * @__NO_SIDE_EFFECTS__
182
196
  */
package/test/package.json CHANGED
@@ -1,15 +1,16 @@
1
1
  {
2
2
  "name": "@dereekb/dbx-cli/test",
3
- "version": "13.38.0",
3
+ "version": "13.40.0",
4
+ "type": "module",
4
5
  "peerDependencies": {
5
- "@dereekb/date": "13.38.0",
6
- "@dereekb/dbx-cli": "13.38.0",
7
- "@dereekb/firebase": "13.38.0",
8
- "@dereekb/firebase-server/test": "13.38.0",
9
- "@dereekb/model": "13.38.0",
10
- "@dereekb/nestjs": "13.38.0",
11
- "@dereekb/rxjs": "13.38.0",
12
- "@dereekb/util": "13.38.0",
6
+ "@dereekb/date": "13.40.0",
7
+ "@dereekb/dbx-cli": "13.40.0",
8
+ "@dereekb/firebase": "13.40.0",
9
+ "@dereekb/firebase-server/test": "13.40.0",
10
+ "@dereekb/model": "13.40.0",
11
+ "@dereekb/nestjs": "13.40.0",
12
+ "@dereekb/rxjs": "13.40.0",
13
+ "@dereekb/util": "13.40.0",
13
14
  "@nestjs/common": "^11.1.19",
14
15
  "arktype": "^2.2.0",
15
16
  "vitest": "4.1.5",
@@ -18,13 +19,12 @@
18
19
  "exports": {
19
20
  "./package.json": "./package.json",
20
21
  ".": {
21
- "module": "./index.esm.js",
22
22
  "types": "./index.d.ts",
23
- "import": "./index.cjs.mjs",
24
- "default": "./index.cjs.js"
23
+ "import": "./index.esm.js",
24
+ "default": "./index.esm.js"
25
25
  }
26
26
  },
27
27
  "module": "./index.esm.js",
28
- "main": "./index.cjs.js",
28
+ "main": "./index.esm.js",
29
29
  "types": "./index.d.ts"
30
- }
30
+ }
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Hapier Creative LLC.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.