@dereekb/dbx-components-mcp 13.12.3 → 13.12.5

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.
@@ -5,7 +5,7 @@ const require = __createRequire(import.meta.url);
5
5
  // packages/dbx-components-mcp/package.json
6
6
  var package_default = {
7
7
  name: "@dereekb/dbx-components-mcp",
8
- version: "13.12.3",
8
+ version: "13.12.5",
9
9
  type: "module",
10
10
  bin: {
11
11
  "dbx-components-mcp": "dbx-components-mcp.js"
@@ -20,20 +20,20 @@ var package_default = {
20
20
  "@angular/core": "21.2.11",
21
21
  "@angular/forms": "21.2.11",
22
22
  "@angular/material": "^21.2.9",
23
- "@dereekb/dbx-cli": "13.12.3",
24
- "@dereekb/dbx-core": "13.12.3",
25
- "@dereekb/dbx-firebase": "13.12.3",
26
- "@dereekb/dbx-form": "13.12.3",
27
- "@dereekb/dbx-web": "13.12.3",
28
- "@dereekb/firebase": "13.12.3",
29
- "@dereekb/firebase-server": "13.12.3",
30
- "@dereekb/rxjs": "13.12.3",
31
- "@dereekb/util": "13.12.3",
23
+ "@dereekb/dbx-cli": "13.12.5",
24
+ "@dereekb/dbx-core": "13.12.5",
25
+ "@dereekb/dbx-firebase": "13.12.5",
26
+ "@dereekb/dbx-form": "13.12.5",
27
+ "@dereekb/dbx-web": "13.12.5",
28
+ "@dereekb/firebase": "13.12.5",
29
+ "@dereekb/firebase-server": "13.12.5",
30
+ "@dereekb/rxjs": "13.12.5",
31
+ "@dereekb/util": "13.12.5",
32
32
  "@uirouter/angular": "21.0.0",
33
33
  rxjs: "^7.8.2"
34
34
  },
35
35
  devDependencies: {
36
- "@dereekb/model": "13.12.3"
36
+ "@dereekb/model": "13.12.5"
37
37
  }
38
38
  };
39
39
 
@@ -130,6 +130,89 @@ var DASH_CHARACTER_PREFIX_INSTANCE = characterPrefixSuffixInstance({
130
130
  prefix: "-"
131
131
  });
132
132
 
133
+ // packages/util/src/lib/test/spec-file-conventions.ts
134
+ var CANONICAL_KINDS = ["crud", "crud-subgroup", "scenario", "scenario-subgroup"];
135
+ var SPEC_SUFFIX = ".spec.ts";
136
+ function classifySpecFile(config) {
137
+ const { filename, parentFolderName } = config;
138
+ let result;
139
+ if (!filename.endsWith(SPEC_SUFFIX)) {
140
+ result = { filename, group: "", kind: "non-spec", subgroups: [], isCanonical: false };
141
+ } else {
142
+ const stem = filename.slice(0, -SPEC_SUFFIX.length);
143
+ const parts = stem.split(".");
144
+ const group = parts[0] ?? "";
145
+ if (group !== parentFolderName) {
146
+ result = { filename, group, kind: "non-group", subgroups: [], isCanonical: false };
147
+ } else {
148
+ const rest = parts.slice(1);
149
+ result = classifyRemainingSegments({ filename, group, rest });
150
+ }
151
+ }
152
+ return result;
153
+ }
154
+ function classifyRemainingSegments(config) {
155
+ const { filename, group, rest } = config;
156
+ let result;
157
+ const crudIdx = rest.indexOf("crud");
158
+ const scenarioIdx = rest.indexOf("scenario");
159
+ if (crudIdx === 0) {
160
+ if (rest.length === 1) {
161
+ result = { filename, group, kind: "crud", subgroups: [], isCanonical: true };
162
+ } else {
163
+ result = { filename, group, kind: "crud-subgroup", subgroups: rest.slice(1), isCanonical: true };
164
+ }
165
+ } else if (scenarioIdx === 0) {
166
+ if (rest.length === 1) {
167
+ result = { filename, group, kind: "scenario", subgroups: [], isCanonical: true };
168
+ } else {
169
+ result = { filename, group, kind: "scenario-subgroup", subgroups: rest.slice(1), isCanonical: true };
170
+ }
171
+ } else if (crudIdx > 0) {
172
+ const subgroups = rest.filter((_, i) => i !== crudIdx);
173
+ const recommendedRename = buildCanonicalFilename({ group, bucket: "crud", subgroups });
174
+ result = { filename, group, kind: "crud-misplaced", subgroups, isCanonical: false, recommendedRename, driftReason: "`crud` segment is not directly after the group name." };
175
+ } else if (scenarioIdx > 0) {
176
+ const subgroups = rest.filter((_, i) => i !== scenarioIdx);
177
+ const recommendedRename = buildCanonicalFilename({ group, bucket: "scenario", subgroups });
178
+ result = { filename, group, kind: "scenario-misplaced", subgroups, isCanonical: false, recommendedRename, driftReason: "`scenario` segment is not directly after the group name." };
179
+ } else if (rest.length === 0) {
180
+ const recommendedRename = buildCanonicalFilename({ group, bucket: "scenario", subgroups: [] });
181
+ result = { filename, group, kind: "no-bucket", subgroups: [], isCanonical: false, recommendedRename, driftReason: "Missing `crud` or `scenario` segment." };
182
+ } else {
183
+ const recommendedRename = buildCanonicalFilename({ group, bucket: "scenario", subgroups: rest });
184
+ result = { filename, group, kind: "no-bucket", subgroups: rest, isCanonical: false, recommendedRename, driftReason: "Missing `crud` or `scenario` segment \u2014 defaulting suggestion to `scenario`." };
185
+ }
186
+ return result;
187
+ }
188
+ function buildCanonicalFilename(config) {
189
+ const { group, bucket, subgroups } = config;
190
+ const tail = subgroups.length === 0 ? "" : `.${subgroups.join(".")}`;
191
+ return `${group}.${bucket}${tail}.spec.ts`;
192
+ }
193
+ function recommendSpecPath(config) {
194
+ const filename = buildCanonicalFilename({ group: config.group, bucket: config.bucket, subgroups: config.subgroups });
195
+ return `${config.apiDir}/src/app/function/${config.group}/${filename}`;
196
+ }
197
+ function recommendBucketsForGroup(config) {
198
+ const crudPath = recommendSpecPath({ apiDir: config.apiDir, group: config.group, bucket: "crud", subgroups: [] });
199
+ const scenarioPath = recommendSpecPath({ apiDir: config.apiDir, group: config.group, bucket: "scenario", subgroups: [] });
200
+ return [
201
+ {
202
+ bucket: "crud",
203
+ label: "CRUD",
204
+ canonicalPath: crudPath,
205
+ summary: "Non-scenario tests of the CRUD function map \u2014 create/read/update/delete + permission/error paths. Add focused buckets as `" + config.group + ".crud.<sub>.spec.ts`."
206
+ },
207
+ {
208
+ bucket: "scenario",
209
+ label: "Scenario",
210
+ canonicalPath: scenarioPath,
211
+ summary: "Multi-step scenarios using fixture chains (mirrors real workflows). Add focused buckets as `" + config.group + ".scenario.<sub>.spec.ts` (chain subgroups freely, e.g. `.scenario.requirement.worker.spec.ts`)."
212
+ }
213
+ ];
214
+ }
215
+
133
216
  // packages/firebase/src/lib/common/auth/oidc/oidc.error.ts
134
217
  var CALL_MODEL_MISSING_OIDC_SCOPE_ERROR_CODE = "CALL_MODEL_MISSING_OIDC_SCOPE";
135
218
 
@@ -27671,6 +27754,7 @@ function extractCrudEntries(source) {
27671
27754
  description: readJsDocSummary(member),
27672
27755
  paramsTypeDescription: paramsDocs?.typeDescription,
27673
27756
  paramsFields: paramsDocs?.fields,
27757
+ paramsHasApiParamsTag: paramsDocs?.hasApiParamsTag,
27674
27758
  resultTypeDescription: resultDocs?.typeDescription,
27675
27759
  resultFields: resultDocs?.fields
27676
27760
  });
@@ -27761,6 +27845,7 @@ function collectVerbEntries(input) {
27761
27845
  description: readJsDocSummary(specMember),
27762
27846
  paramsTypeDescription: paramsDocs2?.typeDescription,
27763
27847
  paramsFields: paramsDocs2?.fields,
27848
+ paramsHasApiParamsTag: paramsDocs2?.hasApiParamsTag,
27764
27849
  resultTypeDescription: resultDocs2?.typeDescription,
27765
27850
  resultFields: resultDocs2?.fields
27766
27851
  });
@@ -27780,6 +27865,7 @@ function collectVerbEntries(input) {
27780
27865
  description: fallbackDescription,
27781
27866
  paramsTypeDescription: paramsDocs?.typeDescription,
27782
27867
  paramsFields: paramsDocs?.fields,
27868
+ paramsHasApiParamsTag: paramsDocs?.hasApiParamsTag,
27783
27869
  resultTypeDescription: resultDocs?.typeDescription,
27784
27870
  resultFields: resultDocs?.fields
27785
27871
  });
@@ -27815,17 +27901,28 @@ function readTypeDocs(sourceFile, typeName) {
27815
27901
  const interfaceDecl = sourceFile.getInterface(typeName);
27816
27902
  if (interfaceDecl) {
27817
27903
  const typeDescription = readJsDocSummary(interfaceDecl);
27904
+ const hasApiParamsTag = hasJsDocFlag(interfaceDecl, "dbxModelApiParams");
27818
27905
  const fields = [];
27819
27906
  for (const property of interfaceDecl.getProperties()) {
27820
27907
  const fieldName = property.getName();
27821
27908
  const description = readJsDocSummary(property);
27822
27909
  const typeNode = property.getTypeNode();
27823
27910
  const typeText = typeNode?.getText().trim() ?? "";
27824
- const field = description ? { name: fieldName, typeText, description } : { name: fieldName, typeText };
27911
+ const adminOnly = hasJsDocFlag(property, "dbxModelApiAdminOnly");
27912
+ const field = {
27913
+ name: fieldName,
27914
+ typeText,
27915
+ ...description ? { description } : {},
27916
+ ...adminOnly ? { accessLevel: "adminOnly" } : {}
27917
+ };
27825
27918
  fields.push(field);
27826
27919
  }
27827
- if (typeDescription || fields.length > 0) {
27828
- result = { typeDescription, fields: fields.length > 0 ? fields : void 0 };
27920
+ if (typeDescription || fields.length > 0 || hasApiParamsTag) {
27921
+ result = {
27922
+ ...typeDescription ? { typeDescription } : {},
27923
+ ...fields.length > 0 ? { fields } : {},
27924
+ hasApiParamsTag
27925
+ };
27829
27926
  }
27830
27927
  } else {
27831
27928
  const typeAlias = sourceFile.getTypeAlias(typeName);
@@ -27838,6 +27935,17 @@ function readTypeDocs(sourceFile, typeName) {
27838
27935
  }
27839
27936
  return result;
27840
27937
  }
27938
+ function hasJsDocFlag(node, tagName) {
27939
+ let result = false;
27940
+ for (const doc of node.getJsDocs()) {
27941
+ for (const tag of doc.getTags()) {
27942
+ if (tag.getTagName() === tagName) {
27943
+ result = true;
27944
+ }
27945
+ }
27946
+ }
27947
+ return result;
27948
+ }
27841
27949
  function readJsDocSummary(node) {
27842
27950
  let result;
27843
27951
  const docs = node.getJsDocs();
@@ -28313,6 +28421,7 @@ function mapEntry(entry, sourceFile, actionLookup) {
28313
28421
  sourceFile,
28314
28422
  paramsJsDoc: entry.paramsTypeDescription,
28315
28423
  paramsFields: mapDocFields(entry.paramsFields),
28424
+ paramsApiParamsTag: entry.paramsHasApiParamsTag,
28316
28425
  resultJsDoc: entry.resultTypeDescription,
28317
28426
  resultFields: mapDocFields(entry.resultFields),
28318
28427
  action,
@@ -28320,14 +28429,13 @@ function mapEntry(entry, sourceFile, actionLookup) {
28320
28429
  };
28321
28430
  }
28322
28431
  function mapDocFields(fields) {
28323
- if (!fields) {
28324
- return [];
28325
- }
28326
- return fields.map((field) => ({
28432
+ const result = fields ? fields.map((field) => ({
28327
28433
  name: field.name,
28328
28434
  typeText: field.typeText,
28329
- jsDoc: field.description
28330
- }));
28435
+ jsDoc: field.description,
28436
+ accessLevel: field.accessLevel ?? "public"
28437
+ })) : [];
28438
+ return result;
28331
28439
  }
28332
28440
  async function collectApiSources(componentAbs) {
28333
28441
  const root = join7(componentAbs, COMPONENT_LIB_SUBPATH);
@@ -28454,7 +28562,7 @@ function formatEntry2(entry) {
28454
28562
  const lines = [`## ${heading}`, ""];
28455
28563
  if (entry.description) lines.push(entry.description, "");
28456
28564
  lines.push(`- Wire key: \`${wireKey}\``, `- Params: ${paramsLabel}`, `- Result: ${resultLabel}`, `- Source: \`${entry.sourceFile}:${entry.line}\``, "");
28457
- appendFieldsSection({ lines, label: "Params", jsDoc: entry.paramsJsDoc, fields: entry.paramsFields });
28565
+ appendFieldsSection({ lines, label: "Params", jsDoc: entry.paramsJsDoc, fields: entry.paramsFields, missingApiParamsTag: entry.paramsApiParamsTag === false });
28458
28566
  appendFieldsSection({ lines, label: "Result", jsDoc: entry.resultJsDoc, fields: entry.resultFields });
28459
28567
  appendActionMethodSection(lines, entry.action);
28460
28568
  appendActionFactorySection(lines, entry.factory);
@@ -28464,10 +28572,11 @@ function formatEntry2(entry) {
28464
28572
  return lines.join("\n").trimEnd();
28465
28573
  }
28466
28574
  function appendFieldsSection(input) {
28467
- const { lines, label, jsDoc, fields } = input;
28468
- if (!jsDoc && fields.length === 0) return;
28575
+ const { lines, label, jsDoc, fields, missingApiParamsTag } = input;
28576
+ if (!jsDoc && fields.length === 0 && !missingApiParamsTag) return;
28469
28577
  lines.push(`### ${label}`);
28470
28578
  if (jsDoc) lines.push("", jsDoc);
28579
+ if (missingApiParamsTag) lines.push("", "_Missing `@dbxModelApiParams` marker on the params interface._");
28471
28580
  if (fields.length > 0) {
28472
28581
  lines.push("");
28473
28582
  for (const field of fields) lines.push(formatField(field));
@@ -28496,8 +28605,9 @@ function formatWireKey(entry) {
28496
28605
  return `${entry.verb}:${entry.specifier}`;
28497
28606
  }
28498
28607
  function formatField(field) {
28608
+ const adminBadge = field.accessLevel === "adminOnly" ? " _(admin only)_" : "";
28499
28609
  const doc = field.jsDoc ? ` \u2014 ${field.jsDoc.split("\n")[0]}` : "";
28500
- return `- \`${field.name}: ${field.typeText}\`${doc}`;
28610
+ return `- \`${field.name}: ${field.typeText}\`${adminBadge}${doc}`;
28501
28611
  }
28502
28612
 
28503
28613
  // packages/dbx-components-mcp/src/tools/model-api-lookup/index.ts
@@ -32590,89 +32700,6 @@ function parseDescribePath2(value) {
32590
32700
  return value.split(">").map((s) => s.trim().toLowerCase()).filter((s) => s.length > 0);
32591
32701
  }
32592
32702
 
32593
- // packages/dbx-components-mcp/src/tools/model-test-shared/conventions.ts
32594
- var CANONICAL_KINDS = ["crud", "crud-subgroup", "scenario", "scenario-subgroup"];
32595
- var SPEC_SUFFIX = ".spec.ts";
32596
- function classifySpecFile(config) {
32597
- const { filename, parentFolderName } = config;
32598
- let result;
32599
- if (!filename.endsWith(SPEC_SUFFIX)) {
32600
- result = { filename, group: "", kind: "non-spec", subgroups: [], isCanonical: false };
32601
- } else {
32602
- const stem = filename.slice(0, -SPEC_SUFFIX.length);
32603
- const parts = stem.split(".");
32604
- const group = parts[0] ?? "";
32605
- if (group !== parentFolderName) {
32606
- result = { filename, group, kind: "non-group", subgroups: [], isCanonical: false };
32607
- } else {
32608
- const rest = parts.slice(1);
32609
- result = classifyRemainingSegments({ filename, group, rest });
32610
- }
32611
- }
32612
- return result;
32613
- }
32614
- function classifyRemainingSegments(config) {
32615
- const { filename, group, rest } = config;
32616
- let result;
32617
- const crudIdx = rest.indexOf("crud");
32618
- const scenarioIdx = rest.indexOf("scenario");
32619
- if (crudIdx === 0) {
32620
- if (rest.length === 1) {
32621
- result = { filename, group, kind: "crud", subgroups: [], isCanonical: true };
32622
- } else {
32623
- result = { filename, group, kind: "crud-subgroup", subgroups: rest.slice(1), isCanonical: true };
32624
- }
32625
- } else if (scenarioIdx === 0) {
32626
- if (rest.length === 1) {
32627
- result = { filename, group, kind: "scenario", subgroups: [], isCanonical: true };
32628
- } else {
32629
- result = { filename, group, kind: "scenario-subgroup", subgroups: rest.slice(1), isCanonical: true };
32630
- }
32631
- } else if (crudIdx > 0) {
32632
- const subgroups = rest.filter((p, i) => i !== crudIdx);
32633
- const recommendedRename = buildCanonicalFilename({ group, bucket: "crud", subgroups });
32634
- result = { filename, group, kind: "crud-misplaced", subgroups, isCanonical: false, recommendedRename, driftReason: "`crud` segment is not directly after the group name." };
32635
- } else if (scenarioIdx > 0) {
32636
- const subgroups = rest.filter((p, i) => i !== scenarioIdx);
32637
- const recommendedRename = buildCanonicalFilename({ group, bucket: "scenario", subgroups });
32638
- result = { filename, group, kind: "scenario-misplaced", subgroups, isCanonical: false, recommendedRename, driftReason: "`scenario` segment is not directly after the group name." };
32639
- } else if (rest.length === 0) {
32640
- const recommendedRename = buildCanonicalFilename({ group, bucket: "scenario", subgroups: [] });
32641
- result = { filename, group, kind: "no-bucket", subgroups: [], isCanonical: false, recommendedRename, driftReason: "Missing `crud` or `scenario` segment." };
32642
- } else {
32643
- const recommendedRename = buildCanonicalFilename({ group, bucket: "scenario", subgroups: rest });
32644
- result = { filename, group, kind: "no-bucket", subgroups: rest, isCanonical: false, recommendedRename, driftReason: "Missing `crud` or `scenario` segment \u2014 defaulting suggestion to `scenario`." };
32645
- }
32646
- return result;
32647
- }
32648
- function buildCanonicalFilename(config) {
32649
- const { group, bucket, subgroups } = config;
32650
- const tail = subgroups.length === 0 ? "" : `.${subgroups.join(".")}`;
32651
- return `${group}.${bucket}${tail}.spec.ts`;
32652
- }
32653
- function recommendSpecPath(config) {
32654
- const filename = buildCanonicalFilename({ group: config.group, bucket: config.bucket, subgroups: config.subgroups });
32655
- return `${config.apiDir}/src/app/function/${config.group}/${filename}`;
32656
- }
32657
- function recommendBucketsForGroup(config) {
32658
- const crudPath = recommendSpecPath({ apiDir: config.apiDir, group: config.group, bucket: "crud", subgroups: [] });
32659
- const scenarioPath = recommendSpecPath({ apiDir: config.apiDir, group: config.group, bucket: "scenario", subgroups: [] });
32660
- return [
32661
- {
32662
- bucket: "crud",
32663
- label: "CRUD",
32664
- canonicalPath: crudPath,
32665
- summary: "Non-scenario tests of the CRUD function map \u2014 create/read/update/delete + permission/error paths. Add focused buckets as `" + config.group + ".crud.<sub>.spec.ts`."
32666
- },
32667
- {
32668
- bucket: "scenario",
32669
- label: "Scenario",
32670
- canonicalPath: scenarioPath,
32671
- summary: "Multi-step scenarios using fixture chains (mirrors real workflows). Add focused buckets as `" + config.group + ".scenario.<sub>.spec.ts` (chain subgroups freely, e.g. `.scenario.requirement.worker.spec.ts`)."
32672
- }
32673
- ];
32674
- }
32675
-
32676
32703
  // packages/dbx-components-mcp/src/tools/model-test-shared/discover.ts
32677
32704
  import { readdir as readdir7, stat as stat11 } from "node:fs/promises";
32678
32705
  import { join as join15, relative as relative13, sep as sep11 } from "node:path";
@@ -0,0 +1,272 @@
1
+ {
2
+ "version": 1,
3
+ "source": "@dereekb/firebase-server",
4
+ "module": "@dereekb/firebase-server",
5
+ "generatedAt": "1970-01-01T00:00:00.000Z",
6
+ "generator": "@dereekb/dbx-components-mcp/scripts/generate-manifests.mjs",
7
+ "entries": [
8
+ {
9
+ "slug": "is-firebase-https-error",
10
+ "name": "isFirebaseHttpsError",
11
+ "kind": "function",
12
+ "category": "firebase-error",
13
+ "module": "@dereekb/firebase-server",
14
+ "subpath": "function/error",
15
+ "signature": "isFirebaseHttpsError(input: unknown | HttpsError): input is HttpsError",
16
+ "description": "Type guard for Firebase {@link HttpsError} instances.",
17
+ "params": [
18
+ {
19
+ "name": "input",
20
+ "type": "unknown | HttpsError",
21
+ "description": "- The value to check.",
22
+ "optional": false
23
+ }
24
+ ],
25
+ "returns": "`true` if the input is a Firebase {@link HttpsError }.",
26
+ "tags": [
27
+ "firebase",
28
+ "https",
29
+ "error",
30
+ "type-guard",
31
+ "server",
32
+ "callable",
33
+ "firebase-error",
34
+ "is",
35
+ "isfirebasehttpserror"
36
+ ],
37
+ "relatedSlugs": [
38
+ "is-firebase-error",
39
+ "firebase-server-error-info"
40
+ ]
41
+ },
42
+ {
43
+ "slug": "is-firebase-error",
44
+ "name": "isFirebaseError",
45
+ "kind": "function",
46
+ "category": "firebase-error",
47
+ "module": "@dereekb/firebase-server",
48
+ "subpath": "function/error",
49
+ "signature": "isFirebaseError(input: unknown | admin.FirebaseError): input is admin.FirebaseError",
50
+ "description": "Type guard for Firebase Admin {@link admin.FirebaseError} instances.",
51
+ "params": [
52
+ {
53
+ "name": "input",
54
+ "type": "unknown | admin.FirebaseError",
55
+ "description": "- The value to check.",
56
+ "optional": false
57
+ }
58
+ ],
59
+ "returns": "`true` if the input is a Firebase Admin {@link admin.FirebaseError }.",
60
+ "tags": [
61
+ "firebase",
62
+ "admin",
63
+ "error",
64
+ "type-guard",
65
+ "server",
66
+ "firebase-error",
67
+ "is",
68
+ "isfirebaseerror"
69
+ ],
70
+ "relatedSlugs": [
71
+ "is-firebase-https-error",
72
+ "firebase-server-error-info"
73
+ ]
74
+ },
75
+ {
76
+ "slug": "firebase-server-error-info",
77
+ "name": "firebaseServerErrorInfo",
78
+ "kind": "function",
79
+ "category": "firebase-error",
80
+ "module": "@dereekb/firebase-server",
81
+ "subpath": "function/error",
82
+ "signature": "firebaseServerErrorInfo(e: unknown): FirebaseServerErrorInfo",
83
+ "description": "Analyzes a caught error and extracts structured Firebase error information.\n\nClassifies the error as an {@link HttpsError}, {@link admin.FirebaseError}, or unknown,\nand extracts any embedded error codes and {@link ServerError} details.",
84
+ "params": [
85
+ {
86
+ "name": "e",
87
+ "type": "unknown",
88
+ "description": "- The caught error to analyze.",
89
+ "optional": false
90
+ }
91
+ ],
92
+ "returns": "Structured {@link FirebaseServerErrorInfo } with classified error details.",
93
+ "tags": [
94
+ "firebase",
95
+ "error",
96
+ "decode",
97
+ "analyze",
98
+ "https",
99
+ "admin",
100
+ "server",
101
+ "classify",
102
+ "server-error",
103
+ "firebase-error",
104
+ "info",
105
+ "firebaseservererrorinfo"
106
+ ],
107
+ "example": "try {\n await someFirebaseOperation();\n} catch (e) {\n const info = firebaseServerErrorInfo(e);\n if (info.serverErrorCode === 'MODEL_NOT_AVAILABLE') { ... }\n}",
108
+ "relatedSlugs": [
109
+ "firebase-server-error-info-code-pair",
110
+ "firebase-server-error-info-server-error-pair",
111
+ "firebase-server-error-info-server-error-code-pair",
112
+ "is-firebase-https-error",
113
+ "is-firebase-error"
114
+ ]
115
+ },
116
+ {
117
+ "slug": "firebase-server-error-info-code-pair",
118
+ "name": "firebaseServerErrorInfoCodePair",
119
+ "kind": "function",
120
+ "category": "firebase-error",
121
+ "module": "@dereekb/firebase-server",
122
+ "subpath": "function/error",
123
+ "signature": "firebaseServerErrorInfoCodePair(e: unknown): [Maybe<FirebaseErrorCode>, FirebaseServerErrorInfo]",
124
+ "description": "Returns a tuple of [firebaseErrorCode, errorInfo] for pattern-matching on Firebase error codes.",
125
+ "params": [
126
+ {
127
+ "name": "e",
128
+ "type": "unknown",
129
+ "description": "- The caught error to analyze.",
130
+ "optional": false
131
+ }
132
+ ],
133
+ "returns": "A tuple of the Firebase error code (if present) and the full error info.",
134
+ "tags": [
135
+ "firebase",
136
+ "error",
137
+ "code",
138
+ "pair",
139
+ "tuple",
140
+ "pattern-match",
141
+ "decode",
142
+ "firebase-error",
143
+ "server",
144
+ "info",
145
+ "firebaseservererrorinfocodepair"
146
+ ],
147
+ "relatedSlugs": [
148
+ "firebase-server-error-info",
149
+ "firebase-server-error-info-server-error-pair",
150
+ "firebase-server-error-info-server-error-code-pair"
151
+ ]
152
+ },
153
+ {
154
+ "slug": "firebase-server-error-info-server-error-pair",
155
+ "name": "firebaseServerErrorInfoServerErrorPair",
156
+ "kind": "function",
157
+ "category": "firebase-error",
158
+ "module": "@dereekb/firebase-server",
159
+ "subpath": "function/error",
160
+ "signature": "firebaseServerErrorInfoServerErrorPair(e: unknown): [Maybe<ServerError>, FirebaseServerErrorInfo]",
161
+ "description": "Returns a tuple of [serverError, errorInfo] for pattern-matching on embedded server error details.",
162
+ "params": [
163
+ {
164
+ "name": "e",
165
+ "type": "unknown",
166
+ "description": "- The caught error to analyze.",
167
+ "optional": false
168
+ }
169
+ ],
170
+ "returns": "A tuple of the server error (if present) and the full error info.",
171
+ "tags": [
172
+ "firebase",
173
+ "error",
174
+ "server-error",
175
+ "pair",
176
+ "tuple",
177
+ "pattern-match",
178
+ "decode",
179
+ "details",
180
+ "firebase-error",
181
+ "server",
182
+ "info",
183
+ "firebaseservererrorinfoservererrorpair"
184
+ ],
185
+ "relatedSlugs": [
186
+ "firebase-server-error-info",
187
+ "firebase-server-error-info-code-pair",
188
+ "firebase-server-error-info-server-error-code-pair"
189
+ ]
190
+ },
191
+ {
192
+ "slug": "firebase-server-error-info-server-error-code-pair",
193
+ "name": "firebaseServerErrorInfoServerErrorCodePair",
194
+ "kind": "function",
195
+ "category": "firebase-error",
196
+ "module": "@dereekb/firebase-server",
197
+ "subpath": "function/error",
198
+ "signature": "firebaseServerErrorInfoServerErrorCodePair(e: unknown): [Maybe<StringErrorCode>, FirebaseServerErrorInfo]",
199
+ "description": "Returns a tuple of [serverErrorCode, errorInfo] for pattern-matching on server error string codes.",
200
+ "params": [
201
+ {
202
+ "name": "e",
203
+ "type": "unknown",
204
+ "description": "- The caught error to analyze.",
205
+ "optional": false
206
+ }
207
+ ],
208
+ "returns": "A tuple of the server error code (if present) and the full error info.",
209
+ "tags": [
210
+ "firebase",
211
+ "error",
212
+ "server-error",
213
+ "code",
214
+ "string-code",
215
+ "pair",
216
+ "tuple",
217
+ "pattern-match",
218
+ "decode",
219
+ "firebase-error",
220
+ "server",
221
+ "info",
222
+ "firebaseservererrorinfoservererrorcodepair"
223
+ ],
224
+ "relatedSlugs": [
225
+ "firebase-server-error-info",
226
+ "firebase-server-error-info-code-pair",
227
+ "firebase-server-error-info-server-error-pair"
228
+ ]
229
+ },
230
+ {
231
+ "slug": "handle-firebase-error",
232
+ "name": "handleFirebaseError",
233
+ "kind": "function",
234
+ "category": "firebase-error",
235
+ "module": "@dereekb/firebase-server",
236
+ "subpath": "function/error",
237
+ "signature": "handleFirebaseError(e: unknown, handleFirebaseErrorFn: ThrowErrorFunction<admin.FirebaseError>): never | void",
238
+ "description": "Handles a caught error if it is a Firebase Admin error, passing it to the given handler function.\n\nIf the error is not a Firebase error (no `code` property), this is a no-op.",
239
+ "params": [
240
+ {
241
+ "name": "e",
242
+ "type": "unknown",
243
+ "description": "- The caught error.",
244
+ "optional": false
245
+ },
246
+ {
247
+ "name": "handleFirebaseErrorFn",
248
+ "type": "ThrowErrorFunction<admin.FirebaseError>",
249
+ "description": "- Handler that receives the typed {@link admin.FirebaseError }.",
250
+ "optional": false
251
+ }
252
+ ],
253
+ "returns": "never | void",
254
+ "tags": [
255
+ "firebase",
256
+ "admin",
257
+ "error",
258
+ "handler",
259
+ "catch",
260
+ "conditional",
261
+ "rethrow",
262
+ "firebase-error",
263
+ "handle",
264
+ "handlefirebaseerror"
265
+ ],
266
+ "relatedSlugs": [
267
+ "is-firebase-error",
268
+ "firebase-server-error-info"
269
+ ]
270
+ }
271
+ ]
272
+ }
@@ -89,6 +89,20 @@
89
89
  ],
90
90
  "notes": "A string key used to test for ownership of a particular set of objects.\n\nFor instance, a database model (or its parent) may have an ownership key associated with it that is compared with the user's current claims."
91
91
  },
92
+ {
93
+ "name": "FirebaseAuthOobCode",
94
+ "package": "@dereekb/firebase",
95
+ "module": "src/lib/common/auth/auth",
96
+ "kind": "semantic-type",
97
+ "definition": "string",
98
+ "baseType": "string",
99
+ "topics": [
100
+ "identifier",
101
+ "string",
102
+ "dereekb-firebase:auth"
103
+ ],
104
+ "notes": "Out-of-band (oob) code returned by Firebase Auth flows such as password reset and email verification.\n\nForwarded back to Firebase (e.g. via `confirmPasswordReset`) to complete the flow."
105
+ },
92
106
  {
93
107
  "name": "DevelopmentFirebaseFunctionSpecifier",
94
108
  "package": "@dereekb/firebase",
@@ -5,6 +5,264 @@
5
5
  "generatedAt": "1970-01-01T00:00:00.000Z",
6
6
  "generator": "@dereekb/dbx-components-mcp/scripts/generate-manifests.mjs",
7
7
  "entries": [
8
+ {
9
+ "slug": "is-client-firebase-error",
10
+ "name": "isClientFirebaseError",
11
+ "kind": "function",
12
+ "category": "firebase-error",
13
+ "module": "@dereekb/firebase",
14
+ "subpath": "client/error/error",
15
+ "signature": "isClientFirebaseError(error: unknown): error is FirebaseError",
16
+ "description": "Type guard that checks whether an error is a client-side {@link FirebaseError} from the `firebase/app` package.\n\nDistinguishes client Firebase errors from server-side errors or generic errors by checking\nfor the `FirebaseError` name and a string `code` property. Used by {@link convertHttpsCallableErrorToReadableError}\nto determine the appropriate error wrapping strategy.",
17
+ "params": [
18
+ {
19
+ "name": "error",
20
+ "type": "unknown",
21
+ "description": "- The value to check.",
22
+ "optional": false
23
+ }
24
+ ],
25
+ "returns": "`true` if the input matches the shape of a client-side `FirebaseError`",
26
+ "tags": [
27
+ "firebase",
28
+ "client",
29
+ "error",
30
+ "type-guard",
31
+ "callable",
32
+ "firebase-error",
33
+ "is",
34
+ "isclientfirebaseerror"
35
+ ],
36
+ "example": "try {\n await someFirebaseOperation();\n} catch (e) {\n if (isClientFirebaseError(e)) {\n console.log(e.code); // e.g., 'auth/user-not-found'\n }\n}",
37
+ "relatedSlugs": [
38
+ "convert-https-callable-error-to-readable-error",
39
+ "firebase-server-error"
40
+ ]
41
+ },
42
+ {
43
+ "slug": "firebase-server-error",
44
+ "name": "FirebaseServerError",
45
+ "kind": "class",
46
+ "category": "firebase-error",
47
+ "module": "@dereekb/firebase",
48
+ "subpath": "client/function/error",
49
+ "signature": "class FirebaseServerError",
50
+ "description": "Client-side representation of an error originating from a Firebase Cloud Function.\n\nWraps a {@link FirebaseError} with structured server error details (status, message, code)\nextracted from the error's `details` property. Extends {@link ServerErrorResponse} for\nconsistent error handling across the application.\n\nTypically created via {@link convertHttpsCallableErrorToReadableError} when an `HttpsCallable`\ninvocation fails with a server-side error that includes structured details.",
51
+ "params": [
52
+ {
53
+ "name": "firebaseError",
54
+ "type": "FirebaseError",
55
+ "description": "",
56
+ "optional": false
57
+ },
58
+ {
59
+ "name": "serverError",
60
+ "type": "ServerError<T>",
61
+ "description": "",
62
+ "optional": false
63
+ }
64
+ ],
65
+ "returns": "FirebaseServerError",
66
+ "tags": [
67
+ "firebase",
68
+ "https",
69
+ "callable",
70
+ "error",
71
+ "server-error",
72
+ "client",
73
+ "response",
74
+ "details",
75
+ "firebase-error",
76
+ "server",
77
+ "firebaseservererror"
78
+ ],
79
+ "example": "try {\n await callableFunction(data);\n} catch (e) {\n if (e instanceof FirebaseServerError) {\n console.log(e.code, e.message, e.firebaseError.code);\n }\n}",
80
+ "relatedSlugs": [
81
+ "convert-https-callable-error-to-readable-error",
82
+ "is-client-firebase-error"
83
+ ]
84
+ },
85
+ {
86
+ "slug": "convert-https-callable-error-to-readable-error",
87
+ "name": "convertHttpsCallableErrorToReadableError",
88
+ "kind": "function",
89
+ "category": "firebase-error",
90
+ "module": "@dereekb/firebase",
91
+ "subpath": "client/function/function.callable",
92
+ "signature": "convertHttpsCallableErrorToReadableError(error: unknown): unknown",
93
+ "description": "Converts errors from `HttpsCallable` calls into more readable error types.\n\nIf the error is a client-side {@link FirebaseError} with `details`, wraps it as a {@link FirebaseServerError}\nto preserve server-side error context. Otherwise, converts it to a generic readable error via `toReadableError`.",
94
+ "params": [
95
+ {
96
+ "name": "error",
97
+ "type": "unknown",
98
+ "description": "- The caught error from an `HttpsCallable` invocation.",
99
+ "optional": false
100
+ }
101
+ ],
102
+ "returns": "A {@link FirebaseServerError } if the error has structured details, or a generic readable error otherwise.",
103
+ "tags": [
104
+ "firebase",
105
+ "https",
106
+ "callable",
107
+ "error",
108
+ "decode",
109
+ "convert",
110
+ "readable",
111
+ "client",
112
+ "server",
113
+ "firebase-error",
114
+ "to",
115
+ "converthttpscallableerrortoreadableerror"
116
+ ],
117
+ "relatedSlugs": [
118
+ "firebase-server-error",
119
+ "is-client-firebase-error",
120
+ "firebase-auth-error-to-readable-error"
121
+ ]
122
+ },
123
+ {
124
+ "slug": "firebase-auth-error-to-readable-error",
125
+ "name": "firebaseAuthErrorToReadableError",
126
+ "kind": "function",
127
+ "category": "firebase-auth",
128
+ "module": "@dereekb/firebase",
129
+ "subpath": "common/auth/auth.error",
130
+ "signature": "firebaseAuthErrorToReadableError(inputError: FirebaseAuthError): ReadableError",
131
+ "description": "Converts a {@link FirebaseAuthError} into a user-friendly {@link ReadableError} with a human-readable message.\n\nMaps known error codes (wrong password, user not found, network errors) to contextual messages\nsuitable for display in the UI.",
132
+ "params": [
133
+ {
134
+ "name": "inputError",
135
+ "type": "FirebaseAuthError",
136
+ "description": "- The Firebase Auth error to convert.",
137
+ "optional": false
138
+ }
139
+ ],
140
+ "returns": "A {@link ReadableError } with a human-readable message suitable for display.",
141
+ "tags": [
142
+ "firebase",
143
+ "auth",
144
+ "error",
145
+ "readable",
146
+ "convert",
147
+ "decode",
148
+ "message",
149
+ "login",
150
+ "signin",
151
+ "firebase-auth",
152
+ "to",
153
+ "firebaseautherrortoreadableerror"
154
+ ],
155
+ "example": "try {\n await signIn(email, password);\n} catch (e) {\n const readable = firebaseAuthErrorToReadableError(e as FirebaseAuthError);\n showToast(readable.message);\n}",
156
+ "relatedSlugs": [
157
+ "convert-https-callable-error-to-readable-error",
158
+ "firebase-server-error"
159
+ ]
160
+ },
161
+ {
162
+ "slug": "firebase-auth-oob-code-data-pair-delimiter",
163
+ "name": "FIREBASE_AUTH_OOB_CODE_DATA_PAIR_DELIMITER",
164
+ "kind": "const",
165
+ "category": "firebase-auth",
166
+ "module": "@dereekb/firebase",
167
+ "subpath": "common/auth/auth",
168
+ "signature": "const FIREBASE_AUTH_OOB_CODE_DATA_PAIR_DELIMITER: \"-\"",
169
+ "description": "Delimiter used when encoding a {@link FirebaseAuthOobCodeDataPair} into a {@link FirebaseAuthOobCode}.\n\nThe encoded form is `${code}-${uid}` and splitting happens on the first delimiter occurrence,\nso this only requires that the generated code/password not contain `-`. The uid is unrestricted\nand may itself contain `-`.",
170
+ "params": [],
171
+ "returns": "\"-\"",
172
+ "tags": [
173
+ "firebase",
174
+ "auth",
175
+ "oob",
176
+ "code",
177
+ "delimiter",
178
+ "constant",
179
+ "firebase-auth",
180
+ "data",
181
+ "pair",
182
+ "firebase_auth_oob_code_data_pair_delimiter"
183
+ ],
184
+ "relatedSlugs": [
185
+ "encode-firebase-auth-oob-code",
186
+ "decode-firebase-auth-oob-code"
187
+ ]
188
+ },
189
+ {
190
+ "slug": "encode-firebase-auth-oob-code",
191
+ "name": "encodeFirebaseAuthOobCode",
192
+ "kind": "function",
193
+ "category": "firebase-auth",
194
+ "module": "@dereekb/firebase",
195
+ "subpath": "common/auth/auth",
196
+ "signature": "encodeFirebaseAuthOobCode(pair: FirebaseAuthOobCodeDataPair): FirebaseAuthOobCode",
197
+ "description": "Encodes a {@link FirebaseAuthOobCodeDataPair} into a URL-safe {@link FirebaseAuthOobCode}.\n\nThe encoded form is `${code}-${uid}` — code first so that splitting on the first delimiter\nstill works even when the uid itself contains `-` (Firebase uids occasionally do).",
198
+ "params": [
199
+ {
200
+ "name": "pair",
201
+ "type": "FirebaseAuthOobCodeDataPair",
202
+ "description": "",
203
+ "optional": false
204
+ }
205
+ ],
206
+ "returns": "FirebaseAuthOobCode",
207
+ "tags": [
208
+ "firebase",
209
+ "auth",
210
+ "oob",
211
+ "code",
212
+ "encode",
213
+ "uid",
214
+ "password",
215
+ "reset",
216
+ "setup",
217
+ "serialize",
218
+ "firebase-auth",
219
+ "encodefirebaseauthoobcode"
220
+ ],
221
+ "example": "encodeFirebaseAuthOobCode({ uid: 'abc-123', code: 'xyz789' }); // 'xyz789-abc-123'",
222
+ "relatedSlugs": [
223
+ "decode-firebase-auth-oob-code",
224
+ "firebase-auth-oob-code-data-pair-delimiter"
225
+ ]
226
+ },
227
+ {
228
+ "slug": "decode-firebase-auth-oob-code",
229
+ "name": "decodeFirebaseAuthOobCode",
230
+ "kind": "function",
231
+ "category": "firebase-auth",
232
+ "module": "@dereekb/firebase",
233
+ "subpath": "common/auth/auth",
234
+ "signature": "decodeFirebaseAuthOobCode(oobCode: FirebaseAuthOobCode): Maybe<FirebaseAuthOobCodeDataPair>",
235
+ "description": "Decodes a {@link FirebaseAuthOobCode} back into its {@link FirebaseAuthOobCodeDataPair}.\n\nSplits on the first `-` so uids containing additional `-` characters survive the round-trip\nintact. Returns null when the input is missing the delimiter or has empty parts.",
236
+ "params": [
237
+ {
238
+ "name": "oobCode",
239
+ "type": "FirebaseAuthOobCode",
240
+ "description": "",
241
+ "optional": false
242
+ }
243
+ ],
244
+ "returns": "Maybe<FirebaseAuthOobCodeDataPair>",
245
+ "tags": [
246
+ "firebase",
247
+ "auth",
248
+ "oob",
249
+ "code",
250
+ "decode",
251
+ "parse",
252
+ "uid",
253
+ "password",
254
+ "reset",
255
+ "setup",
256
+ "deserialize",
257
+ "firebase-auth",
258
+ "decodefirebaseauthoobcode"
259
+ ],
260
+ "example": "decodeFirebaseAuthOobCode('xyz789-abc-123'); // { uid: 'abc-123', code: 'xyz789' }\ndecodeFirebaseAuthOobCode('invalid'); // null",
261
+ "relatedSlugs": [
262
+ "encode-firebase-auth-oob-code",
263
+ "firebase-auth-oob-code-data-pair-delimiter"
264
+ ]
265
+ },
8
266
  {
9
267
  "slug": "new-documents",
10
268
  "name": "newDocuments",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dereekb/dbx-components-mcp",
3
- "version": "13.12.3",
3
+ "version": "13.12.5",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "dbx-components-mcp": "dbx-components-mcp.js"
@@ -15,19 +15,19 @@
15
15
  "@angular/core": "21.2.11",
16
16
  "@angular/forms": "21.2.11",
17
17
  "@angular/material": "^21.2.9",
18
- "@dereekb/dbx-cli": "13.12.3",
19
- "@dereekb/dbx-core": "13.12.3",
20
- "@dereekb/dbx-firebase": "13.12.3",
21
- "@dereekb/dbx-form": "13.12.3",
22
- "@dereekb/dbx-web": "13.12.3",
23
- "@dereekb/firebase": "13.12.3",
24
- "@dereekb/firebase-server": "13.12.3",
25
- "@dereekb/rxjs": "13.12.3",
26
- "@dereekb/util": "13.12.3",
18
+ "@dereekb/dbx-cli": "13.12.5",
19
+ "@dereekb/dbx-core": "13.12.5",
20
+ "@dereekb/dbx-firebase": "13.12.5",
21
+ "@dereekb/dbx-form": "13.12.5",
22
+ "@dereekb/dbx-web": "13.12.5",
23
+ "@dereekb/firebase": "13.12.5",
24
+ "@dereekb/firebase-server": "13.12.5",
25
+ "@dereekb/rxjs": "13.12.5",
26
+ "@dereekb/util": "13.12.5",
27
27
  "@uirouter/angular": "21.0.0",
28
28
  "rxjs": "^7.8.2"
29
29
  },
30
30
  "devDependencies": {
31
- "@dereekb/model": "13.12.3"
31
+ "@dereekb/model": "13.12.5"
32
32
  }
33
33
  }