@dereekb/dbx-cli 13.37.0 → 13.39.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 (106) hide show
  1. package/eslint/package.json +8 -8
  2. package/firebase-api-manifest/main.js +191 -166
  3. package/firebase-api-manifest/package.json +3 -3
  4. package/firestore-query-manifest/main.js +2063 -0
  5. package/firestore-query-manifest/package.json +13 -0
  6. package/firestore-rules/src/firestore-rules-scan.d.ts +89 -0
  7. package/firestore-rules/src/index.d.ts +1 -0
  8. package/generate-firestore-indexes/main.js +2 -2
  9. package/generate-firestore-indexes/package.json +2 -2
  10. package/generate-mcp-manifest/main.js +1 -0
  11. package/generate-mcp-manifest/package.json +3 -3
  12. package/generate-route-manifest/package.json +2 -2
  13. package/index.esm.js +12615 -6863
  14. package/lint-cache/package.json +2 -2
  15. package/manifest-extract/index.esm.js +4 -1
  16. package/manifest-extract/package.json +7 -7
  17. package/manifest-extract/src/lib/types.d.ts +6 -0
  18. package/model-test/LICENSE +21 -0
  19. package/model-test/index.d.ts +1 -0
  20. package/model-test/index.esm.js +5984 -0
  21. package/model-test/package.json +21 -0
  22. package/model-test/src/index.d.ts +41 -0
  23. package/model-test/src/lib/fixture/archetype.d.ts +33 -0
  24. package/model-test/src/lib/fixture/extract.d.ts +37 -0
  25. package/model-test/src/lib/fixture/format.json.d.ts +24 -0
  26. package/model-test/src/lib/fixture/format.markdown.d.ts +23 -0
  27. package/model-test/src/lib/fixture/forward.d.ts +48 -0
  28. package/model-test/src/lib/fixture/framework-fixtures.d.ts +70 -0
  29. package/model-test/src/lib/fixture/inspect.d.ts +22 -0
  30. package/model-test/src/lib/fixture/scaffold.d.ts +74 -0
  31. package/model-test/src/lib/fixture/types.d.ts +175 -0
  32. package/model-test/src/lib/test/discover.d.ts +81 -0
  33. package/model-test/src/lib/test/extract.d.ts +49 -0
  34. package/model-test/src/lib/test/format.hotspots.d.ts +23 -0
  35. package/model-test/src/lib/test/format.json.d.ts +25 -0
  36. package/model-test/src/lib/test/format.list-app.d.ts +30 -0
  37. package/model-test/src/lib/test/format.markdown.d.ts +25 -0
  38. package/model-test/src/lib/test/hotspots.d.ts +98 -0
  39. package/model-test/src/lib/test/inspect.d.ts +32 -0
  40. package/model-test/src/lib/test/search.d.ts +34 -0
  41. package/model-test/src/lib/test/types.d.ts +179 -0
  42. package/package.json +23 -22
  43. package/route/package.json +12 -12
  44. package/src/lib/api/firestore-session.client.d.ts +54 -0
  45. package/src/lib/api/get-args.helper.d.ts +4 -1
  46. package/src/lib/api/get-many.command.d.ts +8 -3
  47. package/src/lib/api/get.command.d.ts +13 -5
  48. package/src/lib/api/index.d.ts +1 -0
  49. package/src/lib/config/env.d.ts +106 -0
  50. package/src/lib/config/firestore-session.cache.d.ts +86 -0
  51. package/src/lib/config/index.d.ts +1 -0
  52. package/src/lib/config/paths.d.ts +3 -1
  53. package/src/lib/context/cli.context.d.ts +87 -3
  54. package/src/lib/doctor/firestore-session.check.d.ts +113 -0
  55. package/src/lib/doctor/index.d.ts +1 -0
  56. package/src/lib/firestore/firestore-get.command.d.ts +28 -0
  57. package/src/lib/firestore/firestore-queries.command.d.ts +26 -0
  58. package/src/lib/firestore/firestore-query.command.d.ts +25 -0
  59. package/src/lib/firestore/firestore.accessor.d.ts +85 -0
  60. package/src/lib/firestore/firestore.collection.d.ts +44 -0
  61. package/src/lib/firestore/firestore.error.d.ts +14 -0
  62. package/src/lib/firestore/firestore.models.d.ts +223 -0
  63. package/src/lib/firestore/firestore.query-params.d.ts +34 -0
  64. package/src/lib/firestore/firestore.query.d.ts +79 -0
  65. package/src/lib/firestore/firestore.read.d.ts +180 -0
  66. package/src/lib/firestore/firestore.session.d.ts +97 -0
  67. package/src/lib/firestore/index.d.ts +13 -0
  68. package/src/lib/firestore/query-info-utils.d.ts +48 -0
  69. package/src/lib/firestore/query-registry.d.ts +32 -0
  70. package/src/lib/index.d.ts +3 -0
  71. package/src/lib/manifest/types.d.ts +117 -0
  72. package/src/lib/mcp-scan/manifest/dbx-docs-ui-examples-schema.d.ts +2 -2
  73. package/src/lib/mcp-scan/manifest/model-snapshot-fields-schema.d.ts +2 -2
  74. package/src/lib/mcp-scan/manifest/pipes-schema.d.ts +2 -2
  75. package/src/lib/mcp-scan/manifest/ui-components-schema.d.ts +2 -2
  76. package/src/lib/mcp-scan/manifest/utils-schema.d.ts +2 -2
  77. package/src/lib/mcp-scan/scan/dbx-docs-ui-examples-extract.d.ts +1 -1
  78. package/src/lib/mcp-scan/scan/extract-models/types.d.ts +5 -0
  79. package/src/lib/mcp-scan/scan/ui-components-extract.d.ts +1 -1
  80. package/src/lib/middleware/auth.middleware.d.ts +6 -0
  81. package/src/lib/runner/run.d.ts +28 -1
  82. package/src/lib/scan-helpers/emit-generated-ts.d.ts +76 -0
  83. package/src/lib/scan-helpers/exported-from-package.d.ts +29 -0
  84. package/src/lib/util/index.d.ts +1 -0
  85. package/src/lib/util/output.d.ts +10 -0
  86. package/src/lib/util/stdin.d.ts +39 -2
  87. package/src/lib/util/table.d.ts +40 -0
  88. package/test/index.esm.js +4 -2
  89. package/test/package.json +14 -14
  90. package/test/src/lib/cli-test.d.ts +12 -2
  91. package/validate/LICENSE +21 -0
  92. package/validate/index.js +16641 -0
  93. package/validate/package.json +11 -0
  94. package/eslint/index.cjs.default.js +0 -1
  95. package/eslint/index.cjs.js +0 -1112
  96. package/eslint/index.cjs.mjs +0 -2
  97. package/index.cjs.js +0 -59813
  98. package/manifest-extract/index.cjs.default.js +0 -1
  99. package/manifest-extract/index.cjs.js +0 -1592
  100. package/manifest-extract/index.cjs.mjs +0 -2
  101. package/route/index.cjs.default.js +0 -1
  102. package/route/index.cjs.js +0 -18
  103. package/route/index.cjs.mjs +0 -2
  104. package/test/index.cjs.default.js +0 -1
  105. package/test/index.cjs.js +0 -381
  106. package/test/index.cjs.mjs +0 -2
@@ -0,0 +1,25 @@
1
+ import type { CommandModule } from 'yargs';
2
+ import { type CliFirestoreQueryManifest } from '../manifest/types';
3
+ /**
4
+ * Default command name for the Firestore query execution command.
5
+ */
6
+ export declare const DEFAULT_FIRESTORE_QUERY_COMMAND_NAME = "firestore-query";
7
+ /**
8
+ * Options accepted by {@link buildFirestoreQueryCommand}.
9
+ */
10
+ export interface BuildFirestoreQueryCommandOptions {
11
+ readonly commandName?: string;
12
+ }
13
+ /**
14
+ * Builds the top-level `firestore-query <query>` command.
15
+ *
16
+ * Executes a catalog entry over the direct Firestore connection, through the app's security rules
17
+ * as the authenticated user.
18
+ *
19
+ * @param manifest - The generated Firestore query manifest.
20
+ * @param options - Optional command-name override.
21
+ * @returns A yargs `CommandModule` for `runCli({ apiCommands })`.
22
+ *
23
+ * @__NO_SIDE_EFFECTS__
24
+ */
25
+ export declare function buildFirestoreQueryCommand(manifest: CliFirestoreQueryManifest, options?: BuildFirestoreQueryCommandOptions): CommandModule;
@@ -0,0 +1,85 @@
1
+ import { type FirebaseAppModelContext, type FirebaseModelsService } from '@dereekb/firebase';
2
+ import { type Maybe } from '@dereekb/util';
3
+ import { type GetModelOverHttpResult, type GetMultipleModelsOverHttpResult } from '../api/call-model.client';
4
+ import { type CliContext } from '../context/cli.context';
5
+ import { type CliFirestoreBinding, type CliFirestoreBindingInput, type CliFirestoreModels } from './firestore.models';
6
+ /**
7
+ * A callable that resolves the app's TYPED direct-Firestore view for the current invocation, plus the
8
+ * binding to wire the CLI with.
9
+ *
10
+ * The one place an app names its `<X>FirestoreCollections`: `cliFirestoreAccessorFactory` captures
11
+ * both `C` and `Y` at the app site, and hands them back on every call — so an action reads through
12
+ * `collections.guestbookCollection` and `serviceFor('guestbook')` at the app's real types instead of
13
+ * rebuilding the collections itself to recover them.
14
+ *
15
+ * @template C - The app's collections type, e.g. `DemoFirestoreCollections`.
16
+ * @template Y - The app's `<app>FirebaseModelServices` type.
17
+ */
18
+ export type CliFirestoreAccessorFactory<C extends object, Y extends FirebaseModelsService<any, any>> = ((context: CliContext) => Promise<CliFirestoreAccessor<C, Y>>) & {
19
+ /**
20
+ * The binding to hand `runCli({ firestore })`, `buildTestCliContext({ firestore })`, and
21
+ * `createFirestoreSessionDoctorCheck({ firestore })`.
22
+ *
23
+ * Sharing THIS object — rather than calling `cliFirestoreBinding` again with the same arguments —
24
+ * is what lets the accessor reuse the context's memoized collections instead of building a second
25
+ * copy: the reuse branch is an identity check, and two separate `cliFirestoreBinding` calls produce
26
+ * two non-identical bindings.
27
+ */
28
+ readonly binding: CliFirestoreBinding<C>;
29
+ };
30
+ /**
31
+ * The typed direct-Firestore view an app's actions read through.
32
+ *
33
+ * A {@link CliFirestoreModels} carrying the app's real `C` / `Y`, plus the two read helpers, so an
34
+ * action never has to import `getModelOverFirestore` alongside it.
35
+ *
36
+ * @template C - The app's collections type.
37
+ * @template Y - The app's `<app>FirebaseModelServices` type.
38
+ */
39
+ export type CliFirestoreAccessor<C extends object, Y extends FirebaseModelsService<any, any>> = CliFirestoreModels<C, Y> & {
40
+ /**
41
+ * Reads one document by model key, returning the same `{ key, data }` envelope
42
+ * `GET /model/<type>/get` returns.
43
+ */
44
+ readonly readModel: <T = unknown>(modelType: string, key: string) => Promise<GetModelOverHttpResult<Maybe<T>>>;
45
+ /**
46
+ * Batch-reads documents by model key, returning the same `{ results, errors }` envelope the model
47
+ * API's `getMany` returns.
48
+ */
49
+ readonly readMultipleModels: <T = unknown>(modelType: string, keys: ReadonlyArray<string>) => Promise<GetMultipleModelsOverHttpResult<Maybe<T>>>;
50
+ };
51
+ /**
52
+ * Registers an app's collections factory + model services once, and returns the accessor its actions
53
+ * read through.
54
+ *
55
+ * Resolution order on each call, three cases:
56
+ *
57
+ * 1. the context was wired with THIS binding (`models.binding === binding`) → reuse its memoized
58
+ * view. The identity check is what makes the `object` → `C` narrowing sound: `collections`
59
+ * provably came from `binding.collections`, which returns `C`.
60
+ * 2. the context has NO binding → build a view from `requireCliFirestoreSession(context)`, so an app
61
+ * can use the accessor in its actions without also passing `runCli({ firestore })`.
62
+ * 3. the context was wired with a DIFFERENT binding → build a second view and `verboseLog` about it,
63
+ * rather than silently asserting that someone else's `collections` is a `C`.
64
+ *
65
+ * @param input - The app's collections factory, model services, and optional per-model override.
66
+ * @returns The callable accessor, carrying {@link CliFirestoreAccessorFactory.binding}.
67
+ *
68
+ * @example
69
+ * ```ts
70
+ * export const demoCliFirestore = cliFirestoreAccessorFactory({
71
+ * collections: makeDemoFirestoreCollections,
72
+ * models: demoFirebaseModelServices
73
+ * });
74
+ *
75
+ * // wiring
76
+ * runCli({ firestore: demoCliFirestore.binding });
77
+ *
78
+ * // in an action
79
+ * const { collections, session } = await demoCliFirestore(input.context);
80
+ * const entries = await collections.guestbookCollection.queryDocument(...).getDocs();
81
+ * ```
82
+ *
83
+ * @__NO_SIDE_EFFECTS__
84
+ */
85
+ export declare function cliFirestoreAccessorFactory<C extends object, Y extends FirebaseModelsService<any, FirebaseAppModelContext<C>>>(input: CliFirestoreBindingInput<C, Y>): CliFirestoreAccessorFactory<C, Y>;
@@ -0,0 +1,44 @@
1
+ import { type FirestoreCollectionLike, type FirestoreModelKey, type FirestoreModelType } from '@dereekb/firebase';
2
+ import { type CliFirestoreQueryScope } from '../manifest/types';
3
+ import { type CliFirestoreModels } from './firestore.models';
4
+ /**
5
+ * Input for {@link cliFirestoreCollectionForQuery}.
6
+ */
7
+ export interface CliFirestoreCollectionForQueryInput {
8
+ readonly models: CliFirestoreModels;
9
+ readonly modelType: FirestoreModelType;
10
+ /**
11
+ * The entry's declared scope. Together with {@link isNested} it decides whether `--parent` is
12
+ * optional, required, or rejected.
13
+ */
14
+ readonly scope: CliFirestoreQueryScope;
15
+ /**
16
+ * Whether the model is a subcollection of some parent.
17
+ */
18
+ readonly isNested: boolean;
19
+ /**
20
+ * The parent document key to narrow to, from `--parent`.
21
+ */
22
+ readonly parentKey?: FirestoreModelKey;
23
+ }
24
+ /**
25
+ * Resolves the collection a catalog entry should execute against, applying `--parent` scoping.
26
+ *
27
+ * The `--parent` rules, and why:
28
+ *
29
+ * | entry | `--parent` |
30
+ * | --- | --- |
31
+ * | `COLLECTION_GROUP` + nested | optional — narrows the group to one parent |
32
+ * | `COLLECTION` + nested | **required** — the COLLECTION-scope composite index may not exist at group scope, so silently widening would turn a working query into a `FAILED_PRECONDITION` |
33
+ * | not nested | rejected — a root collection has no parent to scope to |
34
+ *
35
+ * Narrowing is derived generically rather than per-model: `FirestoreCollectionGroup.config` is
36
+ * public and `makeFirestoreCollectionGroup` accepts any `queryLike`, so re-pointing the group's
37
+ * `queryLike` at `firestoreContext.subcollection(parentRef, collectionName)` scopes it to one
38
+ * parent. `docAtPath` needs no parent modelType — the parent key IS the path.
39
+ *
40
+ * @param input - The models view, the entry's model/scope/nesting, and the optional parent key.
41
+ * @returns The collection to query.
42
+ * @throws {CliError} When `--parent` is missing where required, supplied where rejected, or the registered collection cannot be scoped.
43
+ */
44
+ export declare function cliFirestoreCollectionForQuery(input: CliFirestoreCollectionForQueryInput): FirestoreCollectionLike<unknown>;
@@ -0,0 +1,14 @@
1
+ import { type CliErrorMapper } from '../util/output';
2
+ /**
3
+ * Maps a client-SDK `FirebaseError` onto the CLI's error envelope.
4
+ *
5
+ * Without this a rules rejection falls through `buildErrorOutput` to a bare
6
+ * `{ ok: false, code: 'ERROR' }` — indistinguishable from any other failure, which is exactly the
7
+ * wrong answer for the one error the direct path exists to surface honestly.
8
+ *
9
+ * @param error - The thrown value.
10
+ * @returns The mapped envelope, or `undefined` to defer to the built-in branches.
11
+ *
12
+ * @__NO_SIDE_EFFECTS__
13
+ */
14
+ export declare const cliFirestoreErrorMapper: CliErrorMapper;
@@ -0,0 +1,223 @@
1
+ import { type FirebaseAppModelContext, type FirebaseModelServiceGetter, type FirebaseModelsService, type FirebaseModelsServiceTypes, type FirestoreCollectionLike, type FirestoreContext, type FirestoreDocument, type FirestoreModelKey, type FirestoreModelType, type InContextFirebaseModelCollectionLoader, type InContextFirebaseModelLoader } from '@dereekb/firebase';
2
+ import { type Maybe } from '@dereekb/util';
3
+ import { type CliContext } from '../context/cli.context';
4
+ import { type CliFirestoreSessionContext } from './firestore.session';
5
+ /**
6
+ * The slice of a `FirebaseModelService` the CLI's generic direct-Firestore reads need.
7
+ *
8
+ * Only the two members that never touch `roleMapForModel`: `dbx-cli` reads through Firestore
9
+ * security rules, not through the app's role map, so the permission half of the service is
10
+ * deliberately unused here.
11
+ */
12
+ export interface CliFirestoreModelService {
13
+ readonly loadModelForKey: (key: FirestoreModelKey) => FirestoreDocument<unknown>;
14
+ readonly getFirestoreCollection: () => FirestoreCollectionLike<unknown>;
15
+ }
16
+ /**
17
+ * The callable shape of an app's `<app>FirebaseModelServices`, erased to what the CLI needs.
18
+ */
19
+ export type CliFirestoreModelsService = ((modelType: FirestoreModelType, context: {
20
+ readonly app: unknown;
21
+ }) => CliFirestoreModelService) & {
22
+ allTypes(): FirestoreModelType[];
23
+ };
24
+ /**
25
+ * Input for a {@link CliFirestoreBinding.collectionForModel} override.
26
+ */
27
+ export interface CliFirestoreCollectionForModelInput {
28
+ readonly collections: object;
29
+ readonly modelType: FirestoreModelType;
30
+ readonly parentKey?: FirestoreModelKey;
31
+ }
32
+ /**
33
+ * The one app-supplied hook that makes generic direct-Firestore commands possible.
34
+ *
35
+ * `dbx-cli` cannot import an app's collections factory — that is the whole reason there is no
36
+ * generic direct command without this. Supplying it wires `firestore-get` / `firestore-query`
37
+ * for EVERY registered model at once; there is no per-model codegen.
38
+ *
39
+ * `C` appears in exactly one position — the RETURN of {@link collections} — and that is deliberate.
40
+ * Because the use is purely covariant, `CliFirestoreBinding<DemoFirestoreCollections>` is assignable
41
+ * to `CliFirestoreBinding<object>`, which is what lets `CreateCliInput.firestore` keep accepting a
42
+ * typed binding with no cast and keeps generics out of `CliContext` / `runCli` entirely.
43
+ *
44
+ * Adding `C` (or the models generic `Y`) to {@link models} or to
45
+ * {@link CliFirestoreCollectionForModelInput} would put it in a PARAMETER position, and under
46
+ * `strictFunctionTypes` that destroys the assignability above — cascading generics through
47
+ * `CreateCliInput` → `createAuthMiddleware` → `createCliContext` → `CliContext`. Don't.
48
+ *
49
+ * @template C - The app's collections type, e.g. `DemoFirestoreCollections`.
50
+ */
51
+ export interface CliFirestoreBinding<C extends object = object> {
52
+ /**
53
+ * The app's `make<App>FirestoreCollections`.
54
+ */
55
+ readonly collections: (firestoreContext: FirestoreContext) => C;
56
+ /**
57
+ * The app's `<app>FirebaseModelServices`.
58
+ */
59
+ readonly models: CliFirestoreModelsService;
60
+ /**
61
+ * Escape hatch for models whose registered collection cannot be parent-scoped generically
62
+ * (e.g. a paged-items collection). Return `undefined` to fall through to the derived scoping.
63
+ */
64
+ readonly collectionForModel?: (input: CliFirestoreCollectionForModelInput) => Maybe<FirestoreCollectionLike<unknown>>;
65
+ }
66
+ /**
67
+ * Input for {@link cliFirestoreBinding} and {@link cliFirestoreAccessorFactory}.
68
+ *
69
+ * `Y` sits in a PROPERTY position here, which is safe precisely because this is the INPUT type and
70
+ * never the binding: nothing assigns a `CliFirestoreBindingInput` to `CreateCliInput.firestore`, so
71
+ * the variance rule on {@link CliFirestoreBinding} does not apply. Capturing it is what lets
72
+ * `cliFirestoreAccessorFactory` hand back the app's real model types.
73
+ *
74
+ * @template C - The app's collections type, e.g. `DemoFirestoreCollections`.
75
+ * @template Y - The app's `<app>FirebaseModelServices` type.
76
+ */
77
+ export interface CliFirestoreBindingInput<C extends object, Y extends FirebaseModelsService<any, FirebaseAppModelContext<C>> = FirebaseModelsService<any, FirebaseAppModelContext<C>>> {
78
+ readonly collections: (firestoreContext: FirestoreContext) => C;
79
+ readonly models: Y;
80
+ readonly collectionForModel?: (input: CliFirestoreCollectionForModelInput) => Maybe<FirestoreCollectionLike<unknown>>;
81
+ }
82
+ /**
83
+ * Builds a {@link CliFirestoreBinding} from an app's collections factory and model services.
84
+ *
85
+ * Typed so the app site needs no cast — `C` is carried through on {@link CliFirestoreBinding.collections},
86
+ * and the one erasure the CLI requires (the app's model-service union → {@link CliFirestoreModelService})
87
+ * is absorbed here rather than at every call site.
88
+ *
89
+ * The `{ app: collections }` context handed to the model service is COMPLETE for the two members
90
+ * the CLI uses: `FirebasePermissionContext`, `FirebasePermissionErrorContext` and
91
+ * `FirebaseAuthContext` are all-optional, `firebaseModelsService` self-injects `service`, and
92
+ * neither `loadModelForKey` nor `getFirestoreCollection` reads `auth`.
93
+ *
94
+ * Most apps should reach for {@link cliFirestoreAccessorFactory} instead, which calls this and ALSO
95
+ * hands back a typed accessor for the app's own actions. Use this directly only when the binding is
96
+ * all you need.
97
+ *
98
+ * @param input - The app's collections factory, model services, and optional per-model override.
99
+ * @returns The binding `runCli` accepts, still carrying `C`.
100
+ *
101
+ * @example
102
+ * ```ts
103
+ * runCli({
104
+ * firestore: cliFirestoreBinding({ collections: makeDemoFirestoreCollections, models: demoFirebaseModelServices })
105
+ * });
106
+ * ```
107
+ *
108
+ * @__NO_SIDE_EFFECTS__
109
+ */
110
+ export declare function cliFirestoreBinding<C extends object>(input: CliFirestoreBindingInput<C>): CliFirestoreBinding<C>;
111
+ /**
112
+ * The default `Y` for {@link CliFirestoreModels}: a registry admitting ANY `FirestoreModelType`, with
113
+ * every model erased to `unknown`.
114
+ *
115
+ * Chosen so the defaulted generic form reproduces the pre-`Y` interface member-for-member — which is
116
+ * why `CliContext.getFirestoreModels?: () => Promise<CliFirestoreModels>` needs no change, and why
117
+ * every string-dispatched caller inside `dbx-cli` still compiles.
118
+ */
119
+ export type CliErasedFirebaseModelsService = FirebaseModelsService<Record<FirestoreModelType, FirebaseModelServiceGetter<any, unknown>>, any>;
120
+ /**
121
+ * Resolves the app's REAL `T` / `D` for one registered model type out of its `<app>FirebaseModelServices`.
122
+ *
123
+ * Deliberately only the loader half — {@link CliFirestoreModelService} explains why the permission
124
+ * half (`roleMapForModel`, `requireRole`, `use`) is excluded: `dbx-cli` authorizes through
125
+ * `firestore.rules`, not the app's role map, and the `{ app: collections }` context it hands the
126
+ * service carries no `auth` for a role map to read.
127
+ *
128
+ * @template Y - The app's `<app>FirebaseModelServices` type.
129
+ * @template K - The registered model type to resolve.
130
+ */
131
+ export type CliFirestoreModelServiceForType<Y extends FirebaseModelsService<any, any>, K extends FirebaseModelsServiceTypes<Y>> = Y extends FirebaseModelsService<infer X, infer C> ? (K extends keyof X ? (X[K] extends FirebaseModelServiceGetter<C, infer T, infer D, any> ? InContextFirebaseModelLoader<T, D> & InContextFirebaseModelCollectionLoader<T, D> : never) : never) : never;
132
+ /**
133
+ * The per-invocation, session-bound view of an app's models over a direct Firestore connection.
134
+ *
135
+ * @template C - The app's collections type, e.g. `DemoFirestoreCollections`.
136
+ * @template Y - The app's `<app>FirebaseModelServices` type. Defaults to
137
+ * {@link CliErasedFirebaseModelsService}, which reproduces the erased pre-`Y` interface exactly.
138
+ */
139
+ export interface CliFirestoreModels<C extends object = object, Y extends FirebaseModelsService<any, any> = CliErasedFirebaseModelsService> {
140
+ readonly session: CliFirestoreSessionContext;
141
+ /**
142
+ * The app's collections object, built against the session's `FirestoreContext`.
143
+ */
144
+ readonly collections: C;
145
+ /**
146
+ * The binding the app supplied, for consumers that need `collectionForModel`.
147
+ *
148
+ * Typed `CliFirestoreBinding<C>`, NOT `CliFirestoreBinding<C, Y>` — `Y` must never reach the
149
+ * binding, or the binding stops being assignable to `CliFirestoreBinding<object>`. See the
150
+ * variance note on {@link CliFirestoreBinding}.
151
+ */
152
+ readonly binding: CliFirestoreBinding<C>;
153
+ /**
154
+ * The app's `<app>FirebaseModelServices`, at its real type.
155
+ *
156
+ * Runtime-identical to `binding.models` — the same object — but honestly typed, so callers that
157
+ * hold a typed `CliFirestoreModels` can reach the full service (permissions included) when they
158
+ * genuinely want it, rather than the CLI-erased slice {@link serviceFor} hands back.
159
+ */
160
+ readonly models: Y;
161
+ readonly allTypes: () => FirebaseModelsServiceTypes<Y>[];
162
+ /**
163
+ * Resolves the model service for `modelType`, validating against {@link allTypes} FIRST.
164
+ *
165
+ * The validation is load-bearing, not defensive: `firebaseModelsService` indexes its factory map
166
+ * and calls the result immediately, so an unregistered type surfaces as a bare `TypeError`
167
+ * instead of a `CliError` the CLI can render.
168
+ *
169
+ * An OVERLOAD PAIR, specific-first, and the order is what keeps this non-breaking. A literal
170
+ * (`serviceFor('guestbook')`) satisfies `K extends FirebaseModelsServiceTypes<Y>` and gets the app's
171
+ * real `GuestbookDocument`; a runtime `string` off argv does not, and falls through to the erased
172
+ * signature — which is why every string-dispatched caller in `dbx-cli` compiles untouched. Under
173
+ * the default erased `Y`, `FirebaseModelsServiceTypes<Y>` widens to `FirestoreModelType` and
174
+ * signature 1 collapses into signature 2.
175
+ */
176
+ readonly serviceFor: {
177
+ <K extends FirebaseModelsServiceTypes<Y>>(modelType: K): CliFirestoreModelServiceForType<Y, K>;
178
+ (modelType: FirestoreModelType): CliFirestoreModelService;
179
+ };
180
+ /**
181
+ * Resolves a SHORT COLLECTION NAME (`gb`, `gbe`) to the `modelType` the app registered its service
182
+ * under (`guestbook`, `guestbookEntry`).
183
+ *
184
+ * The query catalog records the collection name, not the model type — that is what
185
+ * `firestore.indexes.json` keys on and what `CliModelManifestEntry.collectionPrefix` joins to — but
186
+ * `<app>FirebaseModelServices` is keyed by model type. The join is derived from the registered
187
+ * collections' own `modelIdentity` rather than from a manifest, so it works for every app with no
188
+ * extra wiring.
189
+ *
190
+ * Memoized: resolving walks `allTypes()` building each service's collection until it matches.
191
+ */
192
+ readonly modelTypeForCollection: (collectionName: string) => FirebaseModelsServiceTypes<Y>;
193
+ }
194
+ /**
195
+ * Resolves the direct-Firestore model view for the current invocation, opening the session on
196
+ * first use.
197
+ *
198
+ * @param context - The live CLI context.
199
+ * @returns The session-bound {@link CliFirestoreModels}.
200
+ * @throws {CliError} When the CLI was not configured with a `firestore` binding, or the session cannot be opened.
201
+ */
202
+ export declare function requireCliFirestoreModels(context: CliContext): Promise<CliFirestoreModels>;
203
+ /**
204
+ * Input for {@link createCliFirestoreModels}.
205
+ */
206
+ export interface CreateCliFirestoreModelsInput<C extends object = object> {
207
+ readonly binding: CliFirestoreBinding<C>;
208
+ readonly session: CliFirestoreSessionContext;
209
+ }
210
+ /**
211
+ * Binds an app's {@link CliFirestoreBinding} to an open session.
212
+ *
213
+ * `Y` is inferred from the caller's annotation rather than from `input` — the binding erased its
214
+ * models to {@link CliFirestoreModelsService} on the way in (it must, for variance), so there is
215
+ * nothing left here to infer it from. {@link cliFirestoreAccessorFactory} is what re-attaches the
216
+ * app's real `Y`, having captured it at the app site.
217
+ *
218
+ * @param input - The binding and the open session.
219
+ * @returns The {@link CliFirestoreModels} view.
220
+ *
221
+ * @__NO_SIDE_EFFECTS__
222
+ */
223
+ export declare function createCliFirestoreModels<C extends object = object, Y extends FirebaseModelsService<any, any> = CliErasedFirebaseModelsService>(input: CreateCliFirestoreModelsInput<C>): CliFirestoreModels<C, Y>;
@@ -0,0 +1,34 @@
1
+ import { type CliFirestoreQueryManifestEntry } from '../manifest/types';
2
+ /**
3
+ * Input for {@link resolveCliFirestoreQueryArgs}.
4
+ */
5
+ export interface ResolveCliFirestoreQueryArgsInput {
6
+ readonly entry: CliFirestoreQueryManifestEntry;
7
+ /**
8
+ * The raw `--params` string, if supplied.
9
+ */
10
+ readonly params?: string;
11
+ /**
12
+ * When true, no date coercion is applied at any level.
13
+ */
14
+ readonly rawParams?: boolean;
15
+ }
16
+ /**
17
+ * Resolves the positional argument list to call a catalog entry's factory with.
18
+ *
19
+ * The contract is POSITIONAL-first, because the single-params-object convention is not universal:
20
+ * the workspace's `*.query.ts` files include zero-arg, single-scalar, two-positional,
21
+ * defaulted-positional, `Maybe<Date>` and `ArrayOrValue<T>` shapes.
22
+ *
23
+ * 1. **omitted** → call with no args; valid only when every param is optional.
24
+ * 2. **JSON array** → spread positionally. Works for every shape.
25
+ * 3. **JSON object** → when the factory takes exactly one param and the key set is not exactly that
26
+ * param's name, the whole object is passed as arg 0 (the single-params-object ergonomic path).
27
+ * Otherwise keys are mapped by param name into positional order.
28
+ * 4. **unparseable** → a `CliError` quoting the parse error and the received string.
29
+ *
30
+ * @param input - The catalog entry and the raw `--params` string.
31
+ * @returns The positional arguments to spread into the factory.
32
+ * @throws {CliError} On any arity, naming, JSON, or date-coercion failure.
33
+ */
34
+ export declare function resolveCliFirestoreQueryArgs(input: ResolveCliFirestoreQueryArgsInput): unknown[];
@@ -0,0 +1,79 @@
1
+ import { type FirestoreModelKey, type FirestoreQueryConstraint } from '@dereekb/firebase';
2
+ import { type CliFirestoreQueryManifestEntry } from '../manifest/types';
3
+ import { type CliFirestoreModels } from './firestore.models';
4
+ /**
5
+ * One row returned by {@link runCliFirestoreQuery}.
6
+ */
7
+ export interface CliFirestoreQueryRow {
8
+ readonly key: FirestoreModelKey;
9
+ readonly id: string;
10
+ readonly data: unknown;
11
+ }
12
+ /**
13
+ * The result envelope of a `firestore-query` run.
14
+ */
15
+ export interface CliFirestoreQueryResult {
16
+ readonly slug: string;
17
+ readonly model: string;
18
+ readonly collection: string;
19
+ readonly scope: string;
20
+ readonly parent?: FirestoreModelKey;
21
+ /**
22
+ * Present unless `--count` was passed.
23
+ */
24
+ readonly rows?: readonly CliFirestoreQueryRow[];
25
+ /**
26
+ * Row count — the length of {@link rows}, or the `countDocs()` result under `--count`.
27
+ */
28
+ readonly count: number;
29
+ readonly source: 'firestore';
30
+ }
31
+ /**
32
+ * Input for {@link runCliFirestoreQuery}.
33
+ */
34
+ export interface RunCliFirestoreQueryInput {
35
+ readonly models: CliFirestoreModels;
36
+ readonly entry: CliFirestoreQueryManifestEntry;
37
+ readonly params?: string;
38
+ readonly rawParams?: boolean;
39
+ readonly parent?: FirestoreModelKey;
40
+ readonly limit?: number;
41
+ /**
42
+ * Return only the count, with no rows.
43
+ */
44
+ readonly count?: boolean;
45
+ }
46
+ /**
47
+ * Resolves the constraint list a catalog entry produces for the supplied `--params`.
48
+ *
49
+ * Split out from {@link runCliFirestoreQuery} so the constraints can be inspected (or executed
50
+ * against a different sink, e.g. a future `--watch`) without running the query.
51
+ *
52
+ * @param input - The constraint inputs.
53
+ * @param input.entry - The catalog entry whose factory is called.
54
+ * @param input.params - The raw `--params` string, if supplied.
55
+ * @param input.rawParams - When true, disables date coercion on the params.
56
+ * @param input.limit - Replaces the factory's own `limit()` when supplied.
57
+ * @returns The resolved constraints.
58
+ * @throws {CliError} When the entry is not invocable, or the params do not fit its signature.
59
+ */
60
+ export declare function cliFirestoreQueryConstraints(input: {
61
+ readonly entry: CliFirestoreQueryManifestEntry;
62
+ readonly params?: string;
63
+ readonly rawParams?: boolean;
64
+ readonly limit?: number;
65
+ }): FirestoreQueryConstraint[];
66
+ /**
67
+ * Executes a catalog entry against Firestore over the direct session.
68
+ *
69
+ * Rows come from `getDocSnapshotDataPairs()` + the per-document converter, which costs ONE read per
70
+ * row. `getDocs()` would cost two: `queryLike` is converter-less on both root collections and
71
+ * groups, so it re-loads every matched document from its ref purely to apply the converter. Going
72
+ * through `pair.document.converter` (rather than `collection.queryLike.withConverter(...)`) also
73
+ * honours per-ref converters, such as a stored-data map keyed by document id.
74
+ *
75
+ * @param input - The models view, the entry, and the run options.
76
+ * @returns The query result envelope.
77
+ * @throws {CliError} On an argument, scoping, or invocability failure. Firestore's own errors (rules, missing index) surface via `cliFirestoreErrorMapper`.
78
+ */
79
+ export declare function runCliFirestoreQuery(input: RunCliFirestoreQueryInput): Promise<CliFirestoreQueryResult>;