@dereekb/dbx-cli 13.11.1 → 13.11.2

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.
@@ -0,0 +1,457 @@
1
+ import { Project, Node } from 'ts-morph';
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
+ var SUPPORTED_VERBS = new Set([
5
+ 'create',
6
+ 'read',
7
+ 'update',
8
+ 'delete',
9
+ 'query'
10
+ ]);
11
+ /**
12
+ * Walks a `<model>.api.ts` source and returns one {@link CrudEntry} per
13
+ * callable leaf (CRUD or standalone). Best-effort: malformed configs return
14
+ * fewer entries rather than throwing.
15
+ *
16
+ * @param source - in-memory source name + text pair to extract
17
+ * @returns the CRUD extraction with group name, model keys, entries, and
18
+ * `*Functions` class name (when present).
19
+ */ // eslint-disable-next-line sonarjs/cognitive-complexity
20
+ function extractCrudEntries(source) {
21
+ var project = new Project({
22
+ useInMemoryFileSystem: true,
23
+ skipAddingFilesFromTsConfig: true
24
+ });
25
+ var sourceFile = project.createSourceFile(source.name, source.text, {
26
+ overwrite: true
27
+ });
28
+ var entries = [];
29
+ var modelKeys = [];
30
+ var crudConfigType = findTypeAliasByEnding(sourceFile, 'ModelCrudFunctionsConfig');
31
+ var groupName = inferGroupName(sourceFile);
32
+ var functionsClassName = findFunctionsClassName(sourceFile);
33
+ var typeDocsCache = new Map();
34
+ var resolveTypeDocs = function resolveTypeDocs(typeName) {
35
+ if (!typeName) {
36
+ return undefined;
37
+ }
38
+ if (typeDocsCache.has(typeName)) {
39
+ return typeDocsCache.get(typeName);
40
+ }
41
+ var docs = readTypeDocs(sourceFile, typeName);
42
+ if (docs) {
43
+ typeDocsCache.set(typeName, docs);
44
+ }
45
+ return docs;
46
+ };
47
+ if (crudConfigType) {
48
+ var literal = crudConfigType.getTypeNode();
49
+ if (literal && Node.isTypeLiteral(literal)) {
50
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
51
+ try {
52
+ for(var _iterator = literal.getMembers()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
53
+ var member = _step.value;
54
+ if (!Node.isPropertySignature(member)) {
55
+ continue;
56
+ }
57
+ var modelName = member.getName();
58
+ modelKeys.push(modelName);
59
+ var valueNode = member.getTypeNode();
60
+ if (!valueNode) {
61
+ continue;
62
+ }
63
+ if (isNullLiteralType(valueNode)) {
64
+ continue;
65
+ }
66
+ if (Node.isTypeLiteral(valueNode)) {
67
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
68
+ try {
69
+ for(var _iterator1 = valueNode.getMembers()[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
70
+ var verbMember = _step1.value;
71
+ if (!Node.isPropertySignature(verbMember)) {
72
+ continue;
73
+ }
74
+ var verbName = verbMember.getName();
75
+ if (!SUPPORTED_VERBS.has(verbName)) {
76
+ continue;
77
+ }
78
+ var verb = verbName;
79
+ var verbValueNode = verbMember.getTypeNode();
80
+ if (!verbValueNode) {
81
+ continue;
82
+ }
83
+ collectVerbEntries({
84
+ modelName: modelName,
85
+ verb: verb,
86
+ valueNode: verbValueNode,
87
+ entries: entries,
88
+ fallbackDescription: readJsDocSummary(verbMember),
89
+ resolveTypeDocs: resolveTypeDocs
90
+ });
91
+ }
92
+ } catch (err) {
93
+ _didIteratorError1 = true;
94
+ _iteratorError1 = err;
95
+ } finally{
96
+ try {
97
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
98
+ _iterator1.return();
99
+ }
100
+ } finally{
101
+ if (_didIteratorError1) {
102
+ throw _iteratorError1;
103
+ }
104
+ }
105
+ }
106
+ }
107
+ }
108
+ } catch (err) {
109
+ _didIteratorError = true;
110
+ _iteratorError = err;
111
+ } finally{
112
+ try {
113
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
114
+ _iterator.return();
115
+ }
116
+ } finally{
117
+ if (_didIteratorError) {
118
+ throw _iteratorError;
119
+ }
120
+ }
121
+ }
122
+ }
123
+ }
124
+ var functionTypeMap = findTypeAliasByEnding(sourceFile, 'FunctionTypeMap');
125
+ if (functionTypeMap) {
126
+ var literal1 = functionTypeMap.getTypeNode();
127
+ if (literal1 && Node.isTypeLiteral(literal1)) {
128
+ var _iteratorNormalCompletion2 = true, _didIteratorError2 = false, _iteratorError2 = undefined;
129
+ try {
130
+ for(var _iterator2 = literal1.getMembers()[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true){
131
+ var member1 = _step2.value;
132
+ if (!Node.isPropertySignature(member1)) {
133
+ continue;
134
+ }
135
+ var key = member1.getName();
136
+ var valueNode1 = member1.getTypeNode();
137
+ var tuple = valueNode1 ? readTupleParamsResult(valueNode1) : undefined;
138
+ var paramsDocs = resolveTypeDocs(tuple === null || tuple === void 0 ? void 0 : tuple.params);
139
+ var resultDocs = resolveTypeDocs(tuple === null || tuple === void 0 ? void 0 : tuple.result);
140
+ entries.push({
141
+ model: key,
142
+ verb: 'standalone',
143
+ specifier: undefined,
144
+ paramsTypeName: tuple === null || tuple === void 0 ? void 0 : tuple.params,
145
+ resultTypeName: tuple === null || tuple === void 0 ? void 0 : tuple.result,
146
+ line: member1.getStartLineNumber(),
147
+ description: readJsDocSummary(member1),
148
+ paramsTypeDescription: paramsDocs === null || paramsDocs === void 0 ? void 0 : paramsDocs.typeDescription,
149
+ paramsFields: paramsDocs === null || paramsDocs === void 0 ? void 0 : paramsDocs.fields,
150
+ resultTypeDescription: resultDocs === null || resultDocs === void 0 ? void 0 : resultDocs.typeDescription,
151
+ resultFields: resultDocs === null || resultDocs === void 0 ? void 0 : resultDocs.fields
152
+ });
153
+ }
154
+ } catch (err) {
155
+ _didIteratorError2 = true;
156
+ _iteratorError2 = err;
157
+ } finally{
158
+ try {
159
+ if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
160
+ _iterator2.return();
161
+ }
162
+ } finally{
163
+ if (_didIteratorError2) {
164
+ throw _iteratorError2;
165
+ }
166
+ }
167
+ }
168
+ }
169
+ }
170
+ return {
171
+ groupName: groupName,
172
+ modelKeys: modelKeys,
173
+ entries: entries,
174
+ functionsClassName: functionsClassName
175
+ };
176
+ }
177
+ function findTypeAliasByEnding(sourceFile, ending) {
178
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
179
+ try {
180
+ for(var _iterator = sourceFile.getTypeAliases()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
181
+ var alias = _step.value;
182
+ if (alias.getName().endsWith(ending) && alias.getTypeNode()) {
183
+ return alias;
184
+ }
185
+ }
186
+ } catch (err) {
187
+ _didIteratorError = true;
188
+ _iteratorError = err;
189
+ } finally{
190
+ try {
191
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
192
+ _iterator.return();
193
+ }
194
+ } finally{
195
+ if (_didIteratorError) {
196
+ throw _iteratorError;
197
+ }
198
+ }
199
+ }
200
+ return undefined;
201
+ }
202
+ function findFunctionsClassName(sourceFile) {
203
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
204
+ try {
205
+ for(var _iterator = sourceFile.getClasses()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
206
+ var cls = _step.value;
207
+ if (!cls.isAbstract()) {
208
+ continue;
209
+ }
210
+ var name = cls.getName();
211
+ if (name === null || name === void 0 ? void 0 : name.endsWith('Functions')) {
212
+ return name;
213
+ }
214
+ }
215
+ } catch (err) {
216
+ _didIteratorError = true;
217
+ _iteratorError = err;
218
+ } finally{
219
+ try {
220
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
221
+ _iterator.return();
222
+ }
223
+ } finally{
224
+ if (_didIteratorError) {
225
+ throw _iteratorError;
226
+ }
227
+ }
228
+ }
229
+ return undefined;
230
+ }
231
+ function inferGroupName(sourceFile) {
232
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
233
+ try {
234
+ for(var _iterator = sourceFile.getTypeAliases()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
235
+ var alias = _step.value;
236
+ var name = alias.getName();
237
+ if (name.endsWith('ModelCrudFunctionsConfig')) {
238
+ var stem = name.slice(0, -'ModelCrudFunctionsConfig'.length);
239
+ if (stem.length > 0) {
240
+ return stem;
241
+ }
242
+ }
243
+ }
244
+ } catch (err) {
245
+ _didIteratorError = true;
246
+ _iteratorError = err;
247
+ } finally{
248
+ try {
249
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
250
+ _iterator.return();
251
+ }
252
+ } finally{
253
+ if (_didIteratorError) {
254
+ throw _iteratorError;
255
+ }
256
+ }
257
+ }
258
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
259
+ try {
260
+ for(var _iterator1 = sourceFile.getTypeAliases()[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
261
+ var alias1 = _step1.value;
262
+ var name1 = alias1.getName();
263
+ if (name1.endsWith('FunctionTypeMap')) {
264
+ var stem1 = name1.slice(0, -'FunctionTypeMap'.length);
265
+ if (stem1.length > 0) {
266
+ return stem1;
267
+ }
268
+ }
269
+ }
270
+ } catch (err) {
271
+ _didIteratorError1 = true;
272
+ _iteratorError1 = err;
273
+ } finally{
274
+ try {
275
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
276
+ _iterator1.return();
277
+ }
278
+ } finally{
279
+ if (_didIteratorError1) {
280
+ throw _iteratorError1;
281
+ }
282
+ }
283
+ }
284
+ return undefined;
285
+ }
286
+ function isNullLiteralType(node) {
287
+ if (Node.isLiteralTypeNode(node)) {
288
+ var literal = node.getLiteral();
289
+ if (Node.isNullLiteral(literal)) {
290
+ return true;
291
+ }
292
+ }
293
+ return false;
294
+ }
295
+ function collectVerbEntries(input) {
296
+ var _readTupleParamsResult;
297
+ var modelName = input.modelName, verb = input.verb, valueNode = input.valueNode, entries = input.entries, fallbackDescription = input.fallbackDescription, resolveTypeDocs = input.resolveTypeDocs;
298
+ if (Node.isTypeLiteral(valueNode)) {
299
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
300
+ try {
301
+ for(var _iterator = valueNode.getMembers()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
302
+ var specMember = _step.value;
303
+ var _readTupleParamsResult1;
304
+ if (!Node.isPropertySignature(specMember)) {
305
+ continue;
306
+ }
307
+ var specifier = specMember.getName();
308
+ var leafNode = specMember.getTypeNode();
309
+ var leaf = leafNode ? (_readTupleParamsResult1 = readTupleParamsResult(leafNode)) !== null && _readTupleParamsResult1 !== void 0 ? _readTupleParamsResult1 : readBareParams(leafNode) : undefined;
310
+ var paramsDocs = resolveTypeDocs(leaf === null || leaf === void 0 ? void 0 : leaf.params);
311
+ var resultDocs = resolveTypeDocs(leaf === null || leaf === void 0 ? void 0 : leaf.result);
312
+ entries.push({
313
+ model: modelName,
314
+ verb: verb,
315
+ specifier: specifier,
316
+ paramsTypeName: leaf === null || leaf === void 0 ? void 0 : leaf.params,
317
+ resultTypeName: leaf === null || leaf === void 0 ? void 0 : leaf.result,
318
+ line: specMember.getStartLineNumber(),
319
+ description: readJsDocSummary(specMember),
320
+ paramsTypeDescription: paramsDocs === null || paramsDocs === void 0 ? void 0 : paramsDocs.typeDescription,
321
+ paramsFields: paramsDocs === null || paramsDocs === void 0 ? void 0 : paramsDocs.fields,
322
+ resultTypeDescription: resultDocs === null || resultDocs === void 0 ? void 0 : resultDocs.typeDescription,
323
+ resultFields: resultDocs === null || resultDocs === void 0 ? void 0 : resultDocs.fields
324
+ });
325
+ }
326
+ } catch (err) {
327
+ _didIteratorError = true;
328
+ _iteratorError = err;
329
+ } finally{
330
+ try {
331
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
332
+ _iterator.return();
333
+ }
334
+ } finally{
335
+ if (_didIteratorError) {
336
+ throw _iteratorError;
337
+ }
338
+ }
339
+ }
340
+ return;
341
+ }
342
+ var leaf1 = (_readTupleParamsResult = readTupleParamsResult(valueNode)) !== null && _readTupleParamsResult !== void 0 ? _readTupleParamsResult : readBareParams(valueNode);
343
+ var paramsDocs1 = resolveTypeDocs(leaf1 === null || leaf1 === void 0 ? void 0 : leaf1.params);
344
+ var resultDocs1 = resolveTypeDocs(leaf1 === null || leaf1 === void 0 ? void 0 : leaf1.result);
345
+ entries.push({
346
+ model: modelName,
347
+ verb: verb,
348
+ specifier: undefined,
349
+ paramsTypeName: leaf1 === null || leaf1 === void 0 ? void 0 : leaf1.params,
350
+ resultTypeName: leaf1 === null || leaf1 === void 0 ? void 0 : leaf1.result,
351
+ line: valueNode.getStartLineNumber(),
352
+ description: fallbackDescription,
353
+ paramsTypeDescription: paramsDocs1 === null || paramsDocs1 === void 0 ? void 0 : paramsDocs1.typeDescription,
354
+ paramsFields: paramsDocs1 === null || paramsDocs1 === void 0 ? void 0 : paramsDocs1.fields,
355
+ resultTypeDescription: resultDocs1 === null || resultDocs1 === void 0 ? void 0 : resultDocs1.typeDescription,
356
+ resultFields: resultDocs1 === null || resultDocs1 === void 0 ? void 0 : resultDocs1.fields
357
+ });
358
+ }
359
+ function readTupleParamsResult(node) {
360
+ if (!Node.isTupleTypeNode(node)) {
361
+ return undefined;
362
+ }
363
+ var elements = node.getElements();
364
+ if (elements.length === 0) {
365
+ return undefined;
366
+ }
367
+ var params = elements[0] ? typeNodeName(elements[0]) : undefined;
368
+ var result = elements[1] ? typeNodeName(elements[1]) : undefined;
369
+ return {
370
+ params: params,
371
+ result: result
372
+ };
373
+ }
374
+ function readBareParams(node) {
375
+ var params = typeNodeName(node);
376
+ if (!params) {
377
+ return undefined;
378
+ }
379
+ return {
380
+ params: params,
381
+ result: undefined
382
+ };
383
+ }
384
+ function typeNodeName(node) {
385
+ if (Node.isTypeReference(node)) {
386
+ return node.getTypeName().getText();
387
+ }
388
+ // Fall back to the raw text for primitive / inline types like `boolean`.
389
+ var text = node.getText().trim();
390
+ return text.length > 0 ? text : undefined;
391
+ }
392
+ function readTypeDocs(sourceFile, typeName) {
393
+ var interfaceDecl = sourceFile.getInterface(typeName);
394
+ if (interfaceDecl) {
395
+ var typeDescription = readJsDocSummary(interfaceDecl);
396
+ var fields = [];
397
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
398
+ try {
399
+ for(var _iterator = interfaceDecl.getProperties()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
400
+ var property = _step.value;
401
+ var _ref;
402
+ var fieldName = property.getName();
403
+ var description = readJsDocSummary(property);
404
+ var typeNode = property.getTypeNode();
405
+ var typeText = (_ref = typeNode === null || typeNode === void 0 ? void 0 : typeNode.getText().trim()) !== null && _ref !== void 0 ? _ref : '';
406
+ var field = description ? {
407
+ name: fieldName,
408
+ typeText: typeText,
409
+ description: description
410
+ } : {
411
+ name: fieldName,
412
+ typeText: typeText
413
+ };
414
+ fields.push(field);
415
+ }
416
+ } catch (err) {
417
+ _didIteratorError = true;
418
+ _iteratorError = err;
419
+ } finally{
420
+ try {
421
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
422
+ _iterator.return();
423
+ }
424
+ } finally{
425
+ if (_didIteratorError) {
426
+ throw _iteratorError;
427
+ }
428
+ }
429
+ }
430
+ if (!typeDescription && fields.length === 0) {
431
+ return undefined;
432
+ }
433
+ return {
434
+ typeDescription: typeDescription,
435
+ fields: fields.length > 0 ? fields : undefined
436
+ };
437
+ }
438
+ var typeAlias = sourceFile.getTypeAlias(typeName);
439
+ if (typeAlias) {
440
+ var typeDescription1 = readJsDocSummary(typeAlias);
441
+ return typeDescription1 ? {
442
+ typeDescription: typeDescription1
443
+ } : undefined;
444
+ }
445
+ return undefined;
446
+ }
447
+ function readJsDocSummary(node) {
448
+ var docs = node.getJsDocs();
449
+ if (docs.length === 0) {
450
+ return undefined;
451
+ }
452
+ var last = docs[docs.length - 1];
453
+ var description = last.getDescription().trim();
454
+ return description.length > 0 ? description : undefined;
455
+ }
456
+
457
+ export { extractCrudEntries };
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "@dereekb/dbx-cli/manifest-extract",
3
+ "version": "13.11.2",
4
+ "sideEffects": false,
5
+ "peerDependencies": {
6
+ "ts-morph": "^21.0.0"
7
+ },
8
+ "exports": {
9
+ "./package.json": "./package.json",
10
+ ".": {
11
+ "module": "./index.esm.js",
12
+ "types": "./index.d.ts",
13
+ "import": "./index.cjs.mjs",
14
+ "default": "./index.cjs.js"
15
+ }
16
+ },
17
+ "module": "./index.esm.js",
18
+ "main": "./index.cjs.js",
19
+ "types": "./index.d.ts"
20
+ }
@@ -0,0 +1,2 @@
1
+ export * from './lib/extract-crud';
2
+ export * from './lib/types';
@@ -0,0 +1,36 @@
1
+ /**
2
+ * CRUD-entry walker for `<model>.api.ts` files.
3
+ *
4
+ * Re-parses the source with ts-morph and walks the `<Group>ModelCrudFunctionsConfig`
5
+ * type literal recursively to enumerate every callable leaf, keyed by
6
+ * (model, verb, specifier). Also enumerates `<Group>FunctionTypeMap` keys as
7
+ * `standalone` entries. The walker returns a flat list of {@link CrudEntry}
8
+ * records suitable for tabular rendering.
9
+ *
10
+ * Distinct from the lighter `summarizeCrudConfigType()` in
11
+ * `dbx-components-mcp`'s `model-validate-api/extract.ts`: that helper only
12
+ * collects top-level keys and bare-leaf params names; this walker preserves
13
+ * the full verb→specifier tree, tuple/result information, and JSDoc on both
14
+ * params and result interfaces.
15
+ *
16
+ * Canonical source for both the MCP server's `dbx_model_api_*` tools and the
17
+ * `dbx-cli-firebase-api-manifest` build CLI.
18
+ */
19
+ import type { CrudExtraction } from './types';
20
+ /**
21
+ * Inputs for {@link extractCrudEntries}.
22
+ */
23
+ export interface ExtractCrudInput {
24
+ readonly name: string;
25
+ readonly text: string;
26
+ }
27
+ /**
28
+ * Walks a `<model>.api.ts` source and returns one {@link CrudEntry} per
29
+ * callable leaf (CRUD or standalone). Best-effort: malformed configs return
30
+ * fewer entries rather than throwing.
31
+ *
32
+ * @param source - in-memory source name + text pair to extract
33
+ * @returns the CRUD extraction with group name, model keys, entries, and
34
+ * `*Functions` class name (when present).
35
+ */
36
+ export declare function extractCrudEntries(source: ExtractCrudInput): CrudExtraction;
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Shared types for the `<model>.api.ts` CRUD walker.
3
+ *
4
+ * A CRUD entry is one callable site in a `<model>.api.ts` file —
5
+ * either a leaf in `<Group>ModelCrudFunctionsConfig` (verb + optional
6
+ * specifier) or a key in `<Group>FunctionTypeMap` (standalone).
7
+ *
8
+ * Consumed both by `dbx-components-mcp`'s `dbx_model_api_*` tools and by the
9
+ * `dbx-cli-firebase-api-manifest` build CLI. Re-exported under
10
+ * `@dereekb/dbx-cli/manifest-extract`.
11
+ */
12
+ export type CrudVerb = 'create' | 'read' | 'update' | 'delete' | 'query' | 'standalone';
13
+ export interface CrudEntryDocField {
14
+ readonly name: string;
15
+ readonly typeText: string;
16
+ readonly description?: string;
17
+ }
18
+ export interface CrudEntry {
19
+ /**
20
+ * Top-level model key from `<Group>ModelCrudFunctionsConfig` (e.g. `profile`,
21
+ * `guestbookEntry`). For standalone entries this is the firebase function
22
+ * key itself.
23
+ */
24
+ readonly model: string;
25
+ readonly verb: CrudVerb;
26
+ /**
27
+ * Specifier sub-key (e.g. `username`, `_`, `subscribeToNotifications`).
28
+ * `undefined` when the verb has no nested specifier object (the value is
29
+ * a bare params reference, e.g. `create: CreateGuestbookParams`), or when
30
+ * the entry is `standalone`.
31
+ */
32
+ readonly specifier: string | undefined;
33
+ /**
34
+ * Bare params type name resolved at the leaf (e.g. `SetProfileUsernameParams`).
35
+ * `undefined` when the leaf could not be resolved to a type reference.
36
+ */
37
+ readonly paramsTypeName: string | undefined;
38
+ /**
39
+ * Result type name when the leaf is a `[Params, Result]` tuple, otherwise
40
+ * `undefined` (implies `void`).
41
+ */
42
+ readonly resultTypeName: string | undefined;
43
+ /**
44
+ * Source line of the leaf property in the type literal.
45
+ */
46
+ readonly line: number;
47
+ /**
48
+ * JSDoc summary on the property signature in `<Group>ModelCrudFunctionsConfig` (or the key
49
+ * in `<Group>FunctionTypeMap`).
50
+ */
51
+ readonly description?: string;
52
+ /**
53
+ * JSDoc summary on the params interface itself (e.g. on `ResetProfilePasswordParams`).
54
+ */
55
+ readonly paramsTypeDescription?: string;
56
+ /**
57
+ * Per-field JSDocs read from the params interface's properties.
58
+ */
59
+ readonly paramsFields?: readonly CrudEntryDocField[];
60
+ /**
61
+ * JSDoc summary on the result interface itself (e.g. on `DownloadProfileArchiveResult`).
62
+ */
63
+ readonly resultTypeDescription?: string;
64
+ /**
65
+ * Per-field JSDocs read from the result interface's properties.
66
+ */
67
+ readonly resultFields?: readonly CrudEntryDocField[];
68
+ }
69
+ export interface CrudExtraction {
70
+ /**
71
+ * Inferred group pascal name (e.g. `Profile`, `Guestbook`).
72
+ */
73
+ readonly groupName: string | undefined;
74
+ /**
75
+ * Top-level model keys declared in `<Group>ModelCrudFunctionsConfig`,
76
+ * including null-valued entries (e.g. `profilePrivate: null`).
77
+ */
78
+ readonly modelKeys: readonly string[];
79
+ readonly entries: readonly CrudEntry[];
80
+ /**
81
+ * Name of the abstract `*Functions` class declared in the source, when present.
82
+ * Used by the manifest build CLI to bind `<APP>_FIREBASE_FUNCTIONS_CONFIG`
83
+ * class identifiers to source files.
84
+ */
85
+ readonly functionsClassName?: string;
86
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dereekb/dbx-cli",
3
- "version": "13.11.1",
3
+ "version": "13.11.2",
4
4
  "sideEffects": false,
5
5
  "bin": {
6
6
  "dbx-cli-generate-firebase-api-manifest": "firebase-api-manifest/main.js"
@@ -9,6 +9,12 @@
9
9
  "./firebase-api-manifest": {
10
10
  "default": "./firebase-api-manifest/main.js"
11
11
  },
12
+ "./manifest-extract": {
13
+ "module": "./manifest-extract/index.esm.js",
14
+ "types": "./manifest-extract/index.d.ts",
15
+ "import": "./manifest-extract/index.cjs.mjs",
16
+ "default": "./manifest-extract/index.cjs.js"
17
+ },
12
18
  "./package.json": "./package.json",
13
19
  ".": {
14
20
  "module": "./index.esm.js",
@@ -18,9 +24,9 @@
18
24
  }
19
25
  },
20
26
  "peerDependencies": {
21
- "@dereekb/firebase": "13.11.1",
22
- "@dereekb/nestjs": "13.11.1",
23
- "@dereekb/util": "13.11.1",
27
+ "@dereekb/firebase": "13.11.2",
28
+ "@dereekb/nestjs": "13.11.2",
29
+ "@dereekb/util": "13.11.2",
24
30
  "arktype": "^2.2.0",
25
31
  "yargs": "^18.0.0"
26
32
  },
@@ -7,7 +7,7 @@ export declare const DEFAULT_CLI_OIDC_SCOPES = "openid profile email";
7
7
  * The `model.*` write scopes filtered out by {@link filterReadOnlyModelScopes}.
8
8
  *
9
9
  * Mirrors the write half of the dbx-components callModel CRUD scope set
10
- * (`CALL_MODEL_OIDC_SCOPES` in `@dereekb/firebase-server/oidc`) — duplicated here so the
10
+ * (`CALL_MODEL_OIDC_SCOPES` in `@dereekb/firebase`) — duplicated here so the
11
11
  * CLI doesn't take a server-side dependency just to know the names.
12
12
  */
13
13
  export declare const MODEL_WRITE_OIDC_SCOPES: readonly ["model.create", "model.update", "model.delete"];