@dereekb/dbx-components-mcp 13.11.15 → 13.11.16

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.11.15",
8
+ version: "13.11.16",
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.11.15",
24
- "@dereekb/dbx-core": "13.11.15",
25
- "@dereekb/dbx-firebase": "13.11.15",
26
- "@dereekb/dbx-form": "13.11.15",
27
- "@dereekb/dbx-web": "13.11.15",
28
- "@dereekb/firebase": "13.11.15",
29
- "@dereekb/firebase-server": "13.11.15",
30
- "@dereekb/rxjs": "13.11.15",
31
- "@dereekb/util": "13.11.15",
23
+ "@dereekb/dbx-cli": "13.11.16",
24
+ "@dereekb/dbx-core": "13.11.16",
25
+ "@dereekb/dbx-firebase": "13.11.16",
26
+ "@dereekb/dbx-form": "13.11.16",
27
+ "@dereekb/dbx-web": "13.11.16",
28
+ "@dereekb/firebase": "13.11.16",
29
+ "@dereekb/firebase-server": "13.11.16",
30
+ "@dereekb/rxjs": "13.11.16",
31
+ "@dereekb/util": "13.11.16",
32
32
  "@uirouter/angular": "21.0.0",
33
33
  rxjs: "^7.8.2"
34
34
  },
35
35
  devDependencies: {
36
- "@dereekb/model": "13.11.15"
36
+ "@dereekb/model": "13.11.16"
37
37
  }
38
38
  };
39
39
 
@@ -89,7 +89,7 @@ var ForgeFieldManifest = type({
89
89
  import { type as type2 } from "arktype";
90
90
  import { Node as Node2 } from "ts-morph";
91
91
 
92
- // packages/dbx-components-mcp/src/scan/scan-extract-utils.ts
92
+ // packages/dbx-cli/src/lib/scan-helpers/scan-extract-utils.ts
93
93
  import { Node, SyntaxKind } from "ts-morph";
94
94
  function unwrapFenced(text) {
95
95
  const trimmed = text.trim();
@@ -833,7 +833,7 @@ var ForgeFieldsScanConfig = type3({
833
833
  var DEFAULT_FORGE_FIELDS_SCAN_OUT_PATH = "forge-fields.mcp.generated.json";
834
834
  var FORGE_FIELDS_SCAN_CONFIG_FILENAME = "dbx-mcp.scan.json";
835
835
 
836
- // packages/dbx-components-mcp/src/scan/scan-io.ts
836
+ // packages/dbx-cli/src/lib/scan-helpers/scan-io.ts
837
837
  import { glob as fsGlob, readFile as nodeReadFile } from "node:fs/promises";
838
838
  import { resolve as resolvePath } from "node:path";
839
839
  import { Project } from "ts-morph";
@@ -3291,11 +3291,11 @@ function formatExtractWarning3(warning) {
3291
3291
  return result;
3292
3292
  }
3293
3293
 
3294
- // packages/dbx-components-mcp/src/scan/model-firebase-index-build-manifest.ts
3294
+ // packages/dbx-cli/firestore-indexes/src/model-firebase-index-build-manifest.ts
3295
3295
  import { relative as relative2, resolve as resolve7 } from "node:path";
3296
3296
  import { type as type18 } from "arktype";
3297
3297
 
3298
- // packages/dbx-components-mcp/src/manifest/model-firebase-index-schema.ts
3298
+ // packages/dbx-cli/firestore-indexes/src/model-firebase-index-schema.ts
3299
3299
  import { type as type16 } from "arktype";
3300
3300
  var DEFAULT_FIRESTORE_INDEX_DENSITY = "SPARSE_ALL";
3301
3301
  var FIRESTORE_WHERE_OPERATORS = ["==", "!=", "<", "<=", ">", ">=", "in", "not-in", "array-contains", "array-contains-any"];
@@ -3374,7 +3374,7 @@ var ModelFirebaseIndexManifest = type16({
3374
3374
  entries: ModelFirebaseIndexEntry.array()
3375
3375
  });
3376
3376
 
3377
- // packages/dbx-components-mcp/src/scan/model-firebase-index-analyze.ts
3377
+ // packages/dbx-cli/firestore-indexes/src/model-firebase-index-analyze.ts
3378
3378
  var EQUALITY_OPERATORS = /* @__PURE__ */ new Set(["==", "in"]);
3379
3379
  var RANGE_OPERATORS = /* @__PURE__ */ new Set(["<", "<=", ">", ">=", "!=", "not-in"]);
3380
3380
  var ARRAY_OPERATORS = /* @__PURE__ */ new Set(["array-contains", "array-contains-any"]);
@@ -3593,10 +3593,10 @@ function fieldOverrideVariantEquals(a, b) {
3593
3593
  return a.queryScope === b.queryScope && a.order === b.order && a.arrayConfig === b.arrayConfig;
3594
3594
  }
3595
3595
 
3596
- // packages/dbx-components-mcp/src/scan/model-firebase-index-extract.ts
3596
+ // packages/dbx-cli/firestore-indexes/src/model-firebase-index-extract.ts
3597
3597
  import { Node as Node6, SyntaxKind as SyntaxKind3 } from "ts-morph";
3598
3598
 
3599
- // packages/dbx-components-mcp/src/registry/firestore-query-helpers.ts
3599
+ // packages/dbx-cli/firestore-indexes/src/firestore-query-helpers.ts
3600
3600
  var FIRESTORE_QUERY_HELPERS = [
3601
3601
  // Inequality helpers — single base where, no orderBy.
3602
3602
  { name: "whereDateIsBefore", fieldArgIndex: 0, parts: [{ kind: "where", operator: "<" }] },
@@ -3729,7 +3729,7 @@ function expandFirestoreQueryHelper(input) {
3729
3729
  return out;
3730
3730
  }
3731
3731
 
3732
- // packages/dbx-components-mcp/src/scan/model-firebase-index-extract.ts
3732
+ // packages/dbx-cli/firestore-indexes/src/model-firebase-index-extract.ts
3733
3733
  var INDEX_MARKER = "dbxModelFirebaseIndex";
3734
3734
  var INDEX_DISPATCHER_TAG = "dbxModelFirebaseIndexDispatcher";
3735
3735
  var INDEX_MODEL_TAG = "dbxModelFirebaseIndexModel";
@@ -4009,7 +4009,7 @@ function composeEntry(input) {
4009
4009
  const example = tags.examples.length > 0 ? tags.examples[0] : "";
4010
4010
  const category = tags.category && tags.category.length > 0 ? tags.category : "misc";
4011
4011
  const tagSet = buildTagSet({ name, slug, summary: tags.summary, explicit: tags.explicitTags, category, model: modelTag });
4012
- const constraintSequences = resolveConstraintSequences({ candidate, tags, name, line, filePath, warnings });
4012
+ const { constraintSequences, dispatcherDelegates } = resolveConstraintSequences({ candidate, tags, name, line, filePath, warnings });
4013
4013
  if (tags.excluded) {
4014
4014
  warnings.push({ kind: "excluded-factory", severity: "warning", name, filePath, line });
4015
4015
  }
@@ -4024,6 +4024,8 @@ function composeEntry(input) {
4024
4024
  skip: tags.skip,
4025
4025
  specOnly: tags.specOnly,
4026
4026
  excluded: tags.excluded,
4027
+ dispatcher: tags.dispatcher,
4028
+ dispatcherDelegates,
4027
4029
  allowArrayContainsAny: tags.allowArrayContainsAny,
4028
4030
  category,
4029
4031
  signature,
@@ -4048,9 +4050,9 @@ function resolveConstraintSequences(input) {
4048
4050
  warnings.push(warning);
4049
4051
  }
4050
4052
  if (tags.skip || tags.specOnly || tags.dispatcher || bodyResult.skipped) {
4051
- return [];
4053
+ return { constraintSequences: [], dispatcherDelegates: bodyResult.dispatcherDelegates };
4052
4054
  }
4053
- return buildConstraintSequences({
4055
+ const constraintSequences = buildConstraintSequences({
4054
4056
  bodyEntries: bodyResult.entries,
4055
4057
  conditionalFields: bodyResult.conditionalFields,
4056
4058
  paths: tags.paths,
@@ -4059,6 +4061,7 @@ function resolveConstraintSequences(input) {
4059
4061
  line,
4060
4062
  warnings
4061
4063
  });
4064
+ return { constraintSequences, dispatcherDelegates: [] };
4062
4065
  }
4063
4066
  function resolveScope2(input) {
4064
4067
  const { tags, resolved, name, filePath, line, warnings } = input;
@@ -4133,13 +4136,14 @@ function extractConstraintsFromBody(input) {
4133
4136
  if (violation !== void 0) {
4134
4137
  warnings.push({ kind: "non-delegating-dispatcher", severity: "error", name: factoryName, callee: violation.callee, filePath, line: violation.line });
4135
4138
  }
4136
- return { entries, conditionalFields: [], warnings, skipped: true };
4139
+ const dispatcherDelegates = body === void 0 ? [] : collectDispatcherDelegates(body);
4140
+ return { entries, conditionalFields: [], warnings, skipped: true, dispatcherDelegates };
4137
4141
  }
4138
4142
  if (body !== void 0) {
4139
4143
  const branch = findFirstBranchNode(body);
4140
4144
  if (branch !== void 0) {
4141
4145
  warnings.push({ kind: "complex-query-body", severity: "error", name: factoryName, branchKind: branch.branchKind, filePath, line: branch.line });
4142
- return { entries, conditionalFields: [], warnings, skipped: true };
4146
+ return { entries, conditionalFields: [], warnings, skipped: true, dispatcherDelegates: [] };
4143
4147
  }
4144
4148
  }
4145
4149
  const initialVisited = /* @__PURE__ */ new Set([buildDeclKey(decl)]);
@@ -4161,7 +4165,29 @@ function extractConstraintsFromBody(input) {
4161
4165
  conditionalFields.push(entry.fieldPath);
4162
4166
  }
4163
4167
  }
4164
- return { entries, conditionalFields, warnings, skipped: false };
4168
+ return { entries, conditionalFields, warnings, skipped: false, dispatcherDelegates: [] };
4169
+ }
4170
+ function collectDispatcherDelegates(bodyNode) {
4171
+ const calls = bodyNode.getDescendantsOfKind(SyntaxKind3.CallExpression);
4172
+ calls.sort((a, b) => a.getStart() - b.getStart());
4173
+ const seen = /* @__PURE__ */ new Set();
4174
+ const out = [];
4175
+ for (const call of calls) {
4176
+ const expression = call.getExpression();
4177
+ if (!Node6.isIdentifier(expression)) {
4178
+ continue;
4179
+ }
4180
+ const name = expression.getText();
4181
+ if (name.length === 0 || seen.has(name)) {
4182
+ continue;
4183
+ }
4184
+ if (name === "where" || name === "orderBy" || getFirestoreQueryHelperDescriptor(name) !== void 0) {
4185
+ continue;
4186
+ }
4187
+ seen.add(name);
4188
+ out.push(name);
4189
+ }
4190
+ return out;
4165
4191
  }
4166
4192
  function walkBodyInto(input) {
4167
4193
  const { decl, forcedConditional } = input;
@@ -4491,7 +4517,7 @@ function buildTagSet(input) {
4491
4517
  return out;
4492
4518
  }
4493
4519
 
4494
- // packages/dbx-components-mcp/src/scan/firestore-model-identity-resolver.ts
4520
+ // packages/dbx-cli/firestore-indexes/src/firestore-model-identity-resolver.ts
4495
4521
  import { Node as Node7, SyntaxKind as SyntaxKind4 } from "ts-morph";
4496
4522
  function buildIdentityResolverFromProject(project) {
4497
4523
  const records = [];
@@ -4602,7 +4628,7 @@ function toCamelCase(typeName) {
4602
4628
  return result;
4603
4629
  }
4604
4630
 
4605
- // packages/dbx-components-mcp/src/scan/model-firebase-index-scan-config-schema.ts
4631
+ // packages/dbx-cli/firestore-indexes/src/model-firebase-index-scan-config-schema.ts
4606
4632
  import { type as type17 } from "arktype";
4607
4633
  var ModelFirebaseIndexScanSection = type17({
4608
4634
  "source?": "string",
@@ -4618,7 +4644,7 @@ var ModelFirebaseIndexScanConfig = type17({
4618
4644
  var DEFAULT_MODEL_FIREBASE_INDEX_SCAN_OUT_PATH = "model-firebase-index.mcp.generated.json";
4619
4645
  var MODEL_FIREBASE_INDEX_SCAN_CONFIG_FILENAME = "dbx-mcp.scan.json";
4620
4646
 
4621
- // packages/dbx-components-mcp/src/scan/model-firebase-index-build-manifest.ts
4647
+ // packages/dbx-cli/firestore-indexes/src/model-firebase-index-build-manifest.ts
4622
4648
  var DEFAULT_READ_FILE7 = defaultReadFile;
4623
4649
  var DEFAULT_GLOBBER5 = defaultGlobber;
4624
4650
  async function buildModelFirebaseIndexManifest(input) {
@@ -4681,8 +4707,13 @@ async function buildModelFirebaseIndexManifest(input) {
4681
4707
  } else {
4682
4708
  const outPath = resolve7(projectRoot, scanSection.out ?? DEFAULT_MODEL_FIREBASE_INDEX_SCAN_OUT_PATH);
4683
4709
  const entryFilePathsBySlug = /* @__PURE__ */ new Map();
4710
+ const dispatcherSummaries = [];
4684
4711
  for (const analyzedEntry of analyzed) {
4685
- entryFilePathsBySlug.set(analyzedEntry.extractedEntry.slug, analyzedEntry.extractedEntry.filePath);
4712
+ const extracted = analyzedEntry.extractedEntry;
4713
+ entryFilePathsBySlug.set(extracted.slug, extracted.filePath);
4714
+ if (extracted.dispatcher) {
4715
+ dispatcherSummaries.push({ slug: extracted.slug, name: extracted.name, delegates: [...extracted.dispatcherDelegates] });
4716
+ }
4686
4717
  }
4687
4718
  outcome = {
4688
4719
  kind: "success",
@@ -4690,7 +4721,8 @@ async function buildModelFirebaseIndexManifest(input) {
4690
4721
  outPath,
4691
4722
  scannedFileCount: filePaths.length,
4692
4723
  extractWarnings: buildWarnings,
4693
- entryFilePathsBySlug
4724
+ entryFilePathsBySlug,
4725
+ dispatcherSummaries
4694
4726
  };
4695
4727
  }
4696
4728
  return outcome;
@@ -8193,111 +8225,7 @@ function formatExtractWarning9(warning) {
8193
8225
  return result;
8194
8226
  }
8195
8227
 
8196
- // packages/dbx-components-mcp/src/scan/generate-firestore-indexes-cli.ts
8197
- import { readFile as nodeReadFile4, writeFile as nodeWriteFile3 } from "node:fs/promises";
8198
- import { resolve as resolve15 } from "node:path";
8199
-
8200
- // packages/dbx-components-mcp/src/registry/model-firebase-index-runtime.ts
8201
- // @__NO_SIDE_EFFECTS__
8202
- function createModelFirebaseIndexRegistry(loaded) {
8203
- const entries = Array.from(loaded.entries.values()).map(toModelFirebaseIndexEntryInfo);
8204
- return /* @__PURE__ */ createModelFirebaseIndexRegistryFromEntries({ entries, loadedSources: loaded.loadedSources });
8205
- }
8206
- // @__NO_SIDE_EFFECTS__
8207
- function createModelFirebaseIndexRegistryFromEntries(input) {
8208
- const all = [...input.entries];
8209
- const bySlug = /* @__PURE__ */ new Map();
8210
- const byName = /* @__PURE__ */ new Map();
8211
- const byCollection = /* @__PURE__ */ new Map();
8212
- const byModel = /* @__PURE__ */ new Map();
8213
- const byModule = /* @__PURE__ */ new Map();
8214
- const byCategory = /* @__PURE__ */ new Map();
8215
- const byTag = /* @__PURE__ */ new Map();
8216
- const collectionSet = /* @__PURE__ */ new Set();
8217
- const modelSet = /* @__PURE__ */ new Set();
8218
- const moduleSet = /* @__PURE__ */ new Set();
8219
- const categorySet = /* @__PURE__ */ new Set();
8220
- for (const entry of all) {
8221
- if (!bySlug.has(entry.slug)) {
8222
- bySlug.set(entry.slug, entry);
8223
- }
8224
- if (!byName.has(entry.name)) {
8225
- byName.set(entry.name, entry);
8226
- }
8227
- pushInto(byCollection, entry.collection, entry);
8228
- pushInto(byModel, entry.model, entry);
8229
- pushInto(byModule, entry.module, entry);
8230
- pushInto(byCategory, entry.category, entry);
8231
- for (const tag of entry.tags) {
8232
- pushInto(byTag, tag.toLowerCase(), entry);
8233
- }
8234
- collectionSet.add(entry.collection);
8235
- modelSet.add(entry.model);
8236
- moduleSet.add(entry.module);
8237
- categorySet.add(entry.category);
8238
- }
8239
- const collections = Array.from(collectionSet).sort((a, b) => a.localeCompare(b));
8240
- const models = Array.from(modelSet).sort((a, b) => a.localeCompare(b));
8241
- const modules = Array.from(moduleSet).sort((a, b) => a.localeCompare(b));
8242
- const categories = Array.from(categorySet).sort((a, b) => a.localeCompare(b));
8243
- return {
8244
- all,
8245
- loadedSources: [...input.loadedSources],
8246
- collections,
8247
- models,
8248
- modules,
8249
- categories,
8250
- findBySlug: (slug) => bySlug.get(slug),
8251
- findByName: (name) => byName.get(name),
8252
- findByCollection: (collection) => byCollection.get(collection) ?? [],
8253
- findByModel: (model) => byModel.get(model) ?? [],
8254
- findByModule: (module) => byModule.get(module) ?? [],
8255
- findByCategory: (category) => byCategory.get(category) ?? [],
8256
- findByTag: (tag) => byTag.get(tag.toLowerCase()) ?? []
8257
- };
8258
- }
8259
- var EMPTY_MODEL_FIREBASE_INDEX_REGISTRY = /* @__PURE__ */ createModelFirebaseIndexRegistryFromEntries({ entries: [], loadedSources: [] });
8260
- function toModelFirebaseIndexEntryInfo(entry) {
8261
- return {
8262
- slug: entry.slug,
8263
- name: entry.name,
8264
- module: entry.module,
8265
- subpath: entry.subpath,
8266
- signature: entry.signature,
8267
- description: entry.description,
8268
- model: entry.model,
8269
- collection: entry.collection,
8270
- isNested: entry.isNested,
8271
- scope: entry.scope,
8272
- manual: entry.manual,
8273
- skip: entry.skip,
8274
- category: entry.category,
8275
- params: entry.params.map((p) => ({ ...p })),
8276
- returns: entry.returns,
8277
- tags: [...entry.tags],
8278
- constraintSequences: entry.constraintSequences.map((s) => ({
8279
- ...s.pathLabel === void 0 ? {} : { pathLabel: s.pathLabel },
8280
- entries: s.entries.map((e) => ({ ...e }))
8281
- })),
8282
- derivedComposites: entry.derivedComposites.map((c) => ({ ...c, fields: c.fields.map((f) => ({ ...f })) })),
8283
- derivedFieldOverrides: entry.derivedFieldOverrides.map((f) => ({ ...f, variants: f.variants.map((v) => ({ ...v })) })),
8284
- example: entry.example ?? "",
8285
- relatedSlugs: entry.relatedSlugs ?? [],
8286
- skillRefs: entry.skillRefs ?? [],
8287
- deprecated: entry.deprecated ?? false,
8288
- since: entry.since ?? ""
8289
- };
8290
- }
8291
- function pushInto(map, key, entry) {
8292
- const existing = map.get(key);
8293
- if (existing === void 0) {
8294
- map.set(key, [entry]);
8295
- } else {
8296
- existing.push(entry);
8297
- }
8298
- }
8299
-
8300
- // packages/dbx-components-mcp/src/scan/firestore-indexes-generate.ts
8228
+ // packages/dbx-cli/firestore-indexes/src/firestore-indexes-generate.ts
8301
8229
  function generateFirestoreIndexesJson(input) {
8302
8230
  const { entries, existingJson } = input;
8303
8231
  const { generatedComposites, overrideVariants } = collectDerivedEntries(entries);
@@ -8523,34 +8451,142 @@ function computeDiff(input) {
8523
8451
  };
8524
8452
  }
8525
8453
 
8526
- // packages/dbx-components-mcp/src/scan/generate-firestore-indexes-cli.ts
8527
- var USAGE12 = [
8528
- "Usage: dbx-components-mcp generate-firestore-indexes --component <dir> [--output <path>] [--check] [--json] [--help]",
8529
- "",
8530
- "Generates `firestore.indexes.json` from `@dbxModelFirebaseIndex`-tagged factories.",
8531
- "",
8532
- "Options:",
8533
- " --component <dir> Required. Relative path to the `-firebase` component package.",
8534
- " --output <path> Output path. Defaults to `firestore.indexes.json` at the cwd.",
8535
- " --check Compare against the on-disk file; exit 1 on drift, do not write.",
8536
- " --json Print the diff summary as JSON instead of human-readable text.",
8537
- " --help Show this message."
8538
- ].join("\n");
8454
+ // packages/dbx-cli/firestore-indexes/src/generate-firestore-indexes-cli.ts
8455
+ import { readFile as nodeReadFile4, writeFile as nodeWriteFile3 } from "node:fs/promises";
8456
+ import { resolve as resolve15 } from "node:path";
8457
+
8458
+ // packages/dbx-cli/firestore-indexes/src/model-firebase-index-runtime.ts
8459
+ // @__NO_SIDE_EFFECTS__
8460
+ function createModelFirebaseIndexRegistry(loaded) {
8461
+ const entries = Array.from(loaded.entries.values()).map(toModelFirebaseIndexEntryInfo);
8462
+ return /* @__PURE__ */ createModelFirebaseIndexRegistryFromEntries({ entries, loadedSources: loaded.loadedSources });
8463
+ }
8464
+ // @__NO_SIDE_EFFECTS__
8465
+ function createModelFirebaseIndexRegistryFromEntries(input) {
8466
+ const all = [...input.entries];
8467
+ const bySlug = /* @__PURE__ */ new Map();
8468
+ const byName = /* @__PURE__ */ new Map();
8469
+ const byCollection = /* @__PURE__ */ new Map();
8470
+ const byModel = /* @__PURE__ */ new Map();
8471
+ const byModule = /* @__PURE__ */ new Map();
8472
+ const byCategory = /* @__PURE__ */ new Map();
8473
+ const byTag = /* @__PURE__ */ new Map();
8474
+ const collectionSet = /* @__PURE__ */ new Set();
8475
+ const modelSet = /* @__PURE__ */ new Set();
8476
+ const moduleSet = /* @__PURE__ */ new Set();
8477
+ const categorySet = /* @__PURE__ */ new Set();
8478
+ for (const entry of all) {
8479
+ if (!bySlug.has(entry.slug)) {
8480
+ bySlug.set(entry.slug, entry);
8481
+ }
8482
+ if (!byName.has(entry.name)) {
8483
+ byName.set(entry.name, entry);
8484
+ }
8485
+ pushInto(byCollection, entry.collection, entry);
8486
+ pushInto(byModel, entry.model, entry);
8487
+ pushInto(byModule, entry.module, entry);
8488
+ pushInto(byCategory, entry.category, entry);
8489
+ for (const tag of entry.tags) {
8490
+ pushInto(byTag, tag.toLowerCase(), entry);
8491
+ }
8492
+ collectionSet.add(entry.collection);
8493
+ modelSet.add(entry.model);
8494
+ moduleSet.add(entry.module);
8495
+ categorySet.add(entry.category);
8496
+ }
8497
+ const collections = Array.from(collectionSet).sort((a, b) => a.localeCompare(b));
8498
+ const models = Array.from(modelSet).sort((a, b) => a.localeCompare(b));
8499
+ const modules = Array.from(moduleSet).sort((a, b) => a.localeCompare(b));
8500
+ const categories = Array.from(categorySet).sort((a, b) => a.localeCompare(b));
8501
+ return {
8502
+ all,
8503
+ loadedSources: [...input.loadedSources],
8504
+ collections,
8505
+ models,
8506
+ modules,
8507
+ categories,
8508
+ findBySlug: (slug) => bySlug.get(slug),
8509
+ findByName: (name) => byName.get(name),
8510
+ findByCollection: (collection) => byCollection.get(collection) ?? [],
8511
+ findByModel: (model) => byModel.get(model) ?? [],
8512
+ findByModule: (module) => byModule.get(module) ?? [],
8513
+ findByCategory: (category) => byCategory.get(category) ?? [],
8514
+ findByTag: (tag) => byTag.get(tag.toLowerCase()) ?? []
8515
+ };
8516
+ }
8517
+ var EMPTY_MODEL_FIREBASE_INDEX_REGISTRY = /* @__PURE__ */ createModelFirebaseIndexRegistryFromEntries({ entries: [], loadedSources: [] });
8518
+ function toModelFirebaseIndexEntryInfo(entry) {
8519
+ return {
8520
+ slug: entry.slug,
8521
+ name: entry.name,
8522
+ module: entry.module,
8523
+ subpath: entry.subpath,
8524
+ signature: entry.signature,
8525
+ description: entry.description,
8526
+ model: entry.model,
8527
+ collection: entry.collection,
8528
+ isNested: entry.isNested,
8529
+ scope: entry.scope,
8530
+ manual: entry.manual,
8531
+ skip: entry.skip,
8532
+ category: entry.category,
8533
+ params: entry.params.map((p) => ({ ...p })),
8534
+ returns: entry.returns,
8535
+ tags: [...entry.tags],
8536
+ constraintSequences: entry.constraintSequences.map((s) => ({
8537
+ ...s.pathLabel === void 0 ? {} : { pathLabel: s.pathLabel },
8538
+ entries: s.entries.map((e) => ({ ...e }))
8539
+ })),
8540
+ derivedComposites: entry.derivedComposites.map((c) => ({ ...c, fields: c.fields.map((f) => ({ ...f })) })),
8541
+ derivedFieldOverrides: entry.derivedFieldOverrides.map((f) => ({ ...f, variants: f.variants.map((v) => ({ ...v })) })),
8542
+ example: entry.example ?? "",
8543
+ relatedSlugs: entry.relatedSlugs ?? [],
8544
+ skillRefs: entry.skillRefs ?? [],
8545
+ deprecated: entry.deprecated ?? false,
8546
+ since: entry.since ?? ""
8547
+ };
8548
+ }
8549
+ function pushInto(map, key, entry) {
8550
+ const existing = map.get(key);
8551
+ if (existing === void 0) {
8552
+ map.set(key, [entry]);
8553
+ } else {
8554
+ existing.push(entry);
8555
+ }
8556
+ }
8557
+
8558
+ // packages/dbx-cli/firestore-indexes/src/generate-firestore-indexes-cli.ts
8559
+ var DEFAULT_BIN_NAME = "dbx-cli-generate-firestore-indexes";
8560
+ function buildUsage(binName) {
8561
+ return [
8562
+ `Usage: ${binName} --component <dir> [--output <path>] [--check] [--json] [--help]`,
8563
+ "",
8564
+ "Generates `firestore.indexes.json` from `@dbxModelFirebaseIndex`-tagged factories.",
8565
+ "",
8566
+ "Options:",
8567
+ " --component <dir> Required. Relative path to the `-firebase` component package.",
8568
+ " --output <path> Output path. Defaults to `firestore.indexes.json` at the cwd.",
8569
+ " --check Compare against the on-disk file; exit 1 on drift, do not write.",
8570
+ " --json Print the diff summary as JSON instead of human-readable text.",
8571
+ " --help Show this message."
8572
+ ].join("\n");
8573
+ }
8539
8574
  async function runGenerateFirestoreIndexesCli(input) {
8540
- const { argv, cwd, generator, readFile: readFile26 = (path) => nodeReadFile4(path, "utf-8"), writeFile: writeFile2 = nodeWriteFile3, stdout = (m) => console.log(m), stderr = (m) => console.error(m) } = input;
8575
+ const { argv, cwd, generator, binName = DEFAULT_BIN_NAME, readFile: readFile26 = (path) => nodeReadFile4(path, "utf-8"), writeFile: writeFile2 = nodeWriteFile3, stdout = (m) => console.log(m), stderr = (m) => console.error(m) } = input;
8576
+ const usage = buildUsage(binName);
8541
8577
  const parsed = parseArgv(argv);
8542
8578
  if (parsed.help) {
8543
- stdout(USAGE12);
8579
+ stdout(usage);
8544
8580
  return { exitCode: 0 };
8545
8581
  }
8546
8582
  if (parsed.error !== void 0) {
8547
8583
  stderr(parsed.error);
8548
- stderr(USAGE12);
8584
+ stderr(usage);
8549
8585
  return { exitCode: 2 };
8550
8586
  }
8551
8587
  if (parsed.component === void 0) {
8552
8588
  stderr("generate-firestore-indexes: --component is required");
8553
- stderr(USAGE12);
8589
+ stderr(usage);
8554
8590
  return { exitCode: 2 };
8555
8591
  }
8556
8592
  const componentAbs = resolve15(cwd, parsed.component);
@@ -22229,7 +22265,7 @@ var RULE_CATALOG = [
22229
22265
  whatItFlags: "A composite index required by tagged factories is missing from the committed `firestore.indexes.json`.",
22230
22266
  whenItApplies: "Every entry in the generated composite set that has no equal entry in the committed JSON.",
22231
22267
  whenItDoesNotApply: "Factories tagged `@dbxModelFirebaseIndexManual` \u2014 their shapes are author-managed and excluded from drift.",
22232
- canonicalFix: "Run the `scan-model-firebase-indexes` / `generate-firestore-indexes` CLIs and commit the regenerated `firestore.indexes.json`."
22268
+ canonicalFix: "Run `dbx-cli-generate-firestore-indexes --component <dir>` (and the `scan-model-firebase-indexes` CLI if the manifest is also stale) and commit the regenerated `firestore.indexes.json`."
22233
22269
  },
22234
22270
  {
22235
22271
  code: "MODEL_FIREBASE_INDEX_COMPOSITE_REMOVED",
@@ -43964,6 +44000,24 @@ function toSubpath(absolutePath, projectRoot) {
43964
44000
  return result;
43965
44001
  }
43966
44002
 
44003
+ // packages/dbx-components-mcp/src/scan/model-firebase-index-dispatcher-credit.ts
44004
+ function buildDispatcherCreditByName(dispatcherSummaries, references) {
44005
+ const out = /* @__PURE__ */ new Map();
44006
+ for (const dispatcher of dispatcherSummaries) {
44007
+ const refs = references.get(dispatcher.slug);
44008
+ const productionCount = refs?.productionCount ?? 0;
44009
+ const specCount = refs?.specCount ?? 0;
44010
+ if (productionCount === 0 && specCount === 0) continue;
44011
+ for (const delegate of dispatcher.delegates) {
44012
+ const existing = out.get(delegate) ?? { productionCount: 0, specCount: 0 };
44013
+ existing.productionCount += productionCount;
44014
+ existing.specCount += specCount;
44015
+ out.set(delegate, existing);
44016
+ }
44017
+ }
44018
+ return out;
44019
+ }
44020
+
43967
44021
  // packages/dbx-components-mcp/src/tools/list-app-model-firebase-index.tool.ts
43968
44022
  var ListAppArgsType4 = type82({
43969
44023
  componentDir: "string",
@@ -44076,7 +44130,8 @@ async function resolveBuildOutcome(input) {
44076
44130
  include: WORKSPACE_FACTORY_SCAN_INCLUDE,
44077
44131
  exclude: WORKSPACE_FACTORY_SCAN_EXCLUDE
44078
44132
  });
44079
- const taggedAll = buildOutcome.manifest.entries.map((entry) => toTaggedFactoryUsage(entry, references.get(entry.slug)));
44133
+ const dispatcherCreditByName = buildDispatcherCreditByName(buildOutcome.dispatcherSummaries, references);
44134
+ const taggedAll = buildOutcome.manifest.entries.map((entry) => toTaggedFactoryUsage(entry, references.get(entry.slug), dispatcherCreditByName.get(entry.name)));
44080
44135
  const tagged = applyTaggedFilters(taggedAll, filters);
44081
44136
  const untagged = filters.includeUntagged ? await collectUntaggedCandidates({ componentAbs, tagged: buildOutcome.manifest.entries }) : [];
44082
44137
  const compositeCount = tagged.reduce((acc, t) => acc + t.composites.length, 0);
@@ -44142,10 +44197,12 @@ function isUnused(t) {
44142
44197
  if (t.skip || t.manual) {
44143
44198
  return false;
44144
44199
  }
44200
+ const totalProduction = t.productionReferenceCount + t.dispatcherCreditedProductionCount;
44201
+ const totalSpec = t.specReferenceCount + t.dispatcherCreditedSpecCount;
44145
44202
  if (t.specOnly) {
44146
- return t.productionReferenceCount === 0 && t.specReferenceCount === 0;
44203
+ return totalProduction === 0 && totalSpec === 0;
44147
44204
  }
44148
- return t.productionReferenceCount === 0;
44205
+ return totalProduction === 0;
44149
44206
  }
44150
44207
  function isSpecOnlyViolation(t) {
44151
44208
  return t.specOnly && t.productionReferenceCount > 0;
@@ -44162,7 +44219,7 @@ function applyTaggedFilters(tagged, filters) {
44162
44219
  });
44163
44220
  }
44164
44221
  var MAX_REFERENCE_SAMPLES = 10;
44165
- function toTaggedFactoryUsage(entry, references) {
44222
+ function toTaggedFactoryUsage(entry, references, dispatcherCredit) {
44166
44223
  const referenceCount = references?.count ?? 0;
44167
44224
  const productionReferenceCount = references?.productionCount ?? 0;
44168
44225
  const specReferenceCount = references?.specCount ?? 0;
@@ -44185,6 +44242,8 @@ function toTaggedFactoryUsage(entry, references) {
44185
44242
  productionReferenceCount,
44186
44243
  specReferenceCount,
44187
44244
  referencedBy,
44245
+ dispatcherCreditedProductionCount: dispatcherCredit?.productionCount ?? 0,
44246
+ dispatcherCreditedSpecCount: dispatcherCredit?.specCount ?? 0,
44188
44247
  composites: entry.derivedComposites.map((c) => ({ ...c, fields: c.fields.map((f) => ({ ...f })) })),
44189
44248
  fieldOverrides: entry.derivedFieldOverrides.map((f) => ({ ...f, variants: f.variants.map((v) => ({ ...v })) }))
44190
44249
  };
@@ -44813,11 +44872,14 @@ function pushDiffViolation(input) {
44813
44872
  }
44814
44873
  var MAX_PRODUCTION_SAMPLES = 5;
44815
44874
  function pushFactoryCallerViolations(input) {
44816
- const { buffer, entry, references, filePath } = input;
44875
+ const { buffer, entry, references, dispatcherCreditByName, filePath } = input;
44817
44876
  if (entry.skip || entry.manual) return;
44818
44877
  const refs = references.get(entry.slug);
44819
- const productionCount = refs?.productionCount ?? 0;
44820
- const specCount = refs?.specCount ?? 0;
44878
+ const directProduction = refs?.productionCount ?? 0;
44879
+ const directSpec = refs?.specCount ?? 0;
44880
+ const credit = dispatcherCreditByName.get(entry.name);
44881
+ const productionCount = directProduction + (credit?.productionCount ?? 0);
44882
+ const specCount = directSpec + (credit?.specCount ?? 0);
44821
44883
  if (entry.specOnly === true) {
44822
44884
  pushSpecOnlyCallerViolations({ buffer, entry, refs, productionCount, specCount, filePath });
44823
44885
  return;
@@ -44899,8 +44961,9 @@ async function buildValidateAppReport(input) {
44899
44961
  include: WORKSPACE_FACTORY_SCAN_INCLUDE,
44900
44962
  exclude: WORKSPACE_FACTORY_SCAN_EXCLUDE
44901
44963
  });
44964
+ const dispatcherCreditByName = buildDispatcherCreditByName(buildOutcome.dispatcherSummaries, references);
44902
44965
  for (const entry of buildOutcome.manifest.entries) {
44903
- pushFactoryCallerViolations({ buffer, entry, references, filePath: buildOutcome.entryFilePathsBySlug.get(entry.slug) });
44966
+ pushFactoryCallerViolations({ buffer, entry, references, dispatcherCreditByName, filePath: buildOutcome.entryFilePathsBySlug.get(entry.slug) });
44904
44967
  }
44905
44968
  if (readError !== void 0) {
44906
44969
  pushViolation10(buffer, {
@@ -45060,7 +45123,7 @@ function formatReportAsMarkdown9(report) {
45060
45123
  if (report.indexesFileExists) {
45061
45124
  lines.push(`Indexes file: \`${report.indexesFile}\``, "");
45062
45125
  } else {
45063
- lines.push(`> \`${report.indexesFile}\` does not exist. Run \`dbx-components-mcp generate-firestore-indexes --component ${report.componentDir}\` to create it.`, "");
45126
+ lines.push(`> \`${report.indexesFile}\` does not exist. Run \`dbx-cli-generate-firestore-indexes --component ${report.componentDir}\` to create it.`, "");
45064
45127
  }
45065
45128
  if (report.drift) {
45066
45129
  lines.push("## \u274C Drift detected", "");
@@ -52205,7 +52268,8 @@ async function main() {
52205
52268
  const result = await runGenerateFirestoreIndexesCli({
52206
52269
  argv: argv.slice(1),
52207
52270
  cwd: process.cwd(),
52208
- generator: `@dereekb/dbx-components-mcp@${package_default.version}`
52271
+ generator: `@dereekb/dbx-components-mcp@${package_default.version}`,
52272
+ binName: "dbx-components-mcp generate-firestore-indexes"
52209
52273
  });
52210
52274
  exitCode = result.exitCode;
52211
52275
  } else {
@@ -866,6 +866,146 @@
866
866
  "date-cell-index-range"
867
867
  ]
868
868
  },
869
+ {
870
+ "slug": "date-cell-schedule-encoded-week-regex",
871
+ "name": "DATE_CELL_SCHEDULE_ENCODED_WEEK_REGEX",
872
+ "kind": "const",
873
+ "category": "date",
874
+ "module": "@dereekb/date",
875
+ "subpath": "date/date.cell.schedule",
876
+ "signature": "const DATE_CELL_SCHEDULE_ENCODED_WEEK_REGEX: RegExp",
877
+ "description": "Regex that loosely validates a {@link DateCellScheduleEncodedWeek}.\n\nMatches zero-to-nine digit characters (any of `0-9`). Does not enforce ascending order or uniqueness of\ndigits — use {@link isDateCellScheduleEncodedWeek} for a runtime check that mirrors the type, or\n{@link dateCellScheduleEncodedWeek} to build a guaranteed-valid encoding from {@link DateCellScheduleDayCode}\nvalues.",
878
+ "params": [],
879
+ "returns": "RegExp",
880
+ "tags": [
881
+ "date",
882
+ "schedule",
883
+ "encoded",
884
+ "week",
885
+ "regex",
886
+ "validate",
887
+ "days",
888
+ "cell",
889
+ "date_cell_schedule_encoded_week_regex"
890
+ ],
891
+ "relatedSlugs": [
892
+ "is-date-cell-schedule-encoded-week",
893
+ "date-cell-schedule-encoded-week"
894
+ ]
895
+ },
896
+ {
897
+ "slug": "is-date-cell-schedule-encoded-week",
898
+ "name": "isDateCellScheduleEncodedWeek",
899
+ "kind": "function",
900
+ "category": "date",
901
+ "module": "@dereekb/date",
902
+ "subpath": "date/date.cell.schedule",
903
+ "signature": "isDateCellScheduleEncodedWeek(input: string): input is DateCellScheduleEncodedWeek",
904
+ "description": "Type guard that returns true if the input matches the {@link DATE_CELL_SCHEDULE_ENCODED_WEEK_REGEX} encoded-week format.\n\nThe regex check is loose — it allows duplicate digits and any digit ordering. To produce a canonically simplified\nencoding, use {@link dateCellScheduleEncodedWeek}.",
905
+ "params": [
906
+ {
907
+ "name": "input",
908
+ "type": "string",
909
+ "description": "- String to validate against the encoded week regex.",
910
+ "optional": false
911
+ }
912
+ ],
913
+ "returns": "Whether the string matches the encoded week format.",
914
+ "tags": [
915
+ "date",
916
+ "schedule",
917
+ "encoded",
918
+ "week",
919
+ "type-guard",
920
+ "validate",
921
+ "check",
922
+ "days",
923
+ "is",
924
+ "cell",
925
+ "isdatecellscheduleencodedweek"
926
+ ],
927
+ "example": "isDateCellScheduleEncodedWeek('24'); // true (Mon + Wed)\nisDateCellScheduleEncodedWeek('8'); // true (WEEKDAY shorthand)\nisDateCellScheduleEncodedWeek(''); // true (no days)\nisDateCellScheduleEncodedWeek('abc'); // false",
928
+ "relatedSlugs": [
929
+ "date-cell-schedule-encoded-week-regex",
930
+ "is-empty-date-cell-schedule-encoded-week",
931
+ "date-cell-schedule-encoded-week"
932
+ ]
933
+ },
934
+ {
935
+ "slug": "is-empty-date-cell-schedule-encoded-week",
936
+ "name": "isEmptyDateCellScheduleEncodedWeek",
937
+ "kind": "function",
938
+ "category": "date",
939
+ "module": "@dereekb/date",
940
+ "subpath": "date/date.cell.schedule",
941
+ "signature": "isEmptyDateCellScheduleEncodedWeek(input: string): input is DateCellScheduleEncodedWeek",
942
+ "description": "Returns true if the input represents an empty (no days selected) {@link DateCellScheduleEncodedWeek}.\n\nBoth the empty string `''` and `'0'` are treated as empty since `0` corresponds to\n{@link DateCellScheduleDayCode.NONE}, the no-op day code.",
943
+ "params": [
944
+ {
945
+ "name": "input",
946
+ "type": "string",
947
+ "description": "- String to check for emptiness.",
948
+ "optional": false
949
+ }
950
+ ],
951
+ "returns": "Whether the encoded week represents no selected days.",
952
+ "tags": [
953
+ "date",
954
+ "schedule",
955
+ "encoded",
956
+ "week",
957
+ "empty",
958
+ "check",
959
+ "type-guard",
960
+ "days",
961
+ "is",
962
+ "cell",
963
+ "isemptydatecellscheduleencodedweek"
964
+ ],
965
+ "example": "isEmptyDateCellScheduleEncodedWeek(''); // true\nisEmptyDateCellScheduleEncodedWeek('0'); // true (NONE code)\nisEmptyDateCellScheduleEncodedWeek('8'); // false (WEEKDAY)\nisEmptyDateCellScheduleEncodedWeek('24'); // false (Mon + Wed)",
966
+ "relatedSlugs": [
967
+ "is-date-cell-schedule-encoded-week",
968
+ "date-cell-schedule-encoded-week"
969
+ ]
970
+ },
971
+ {
972
+ "slug": "date-cell-schedule-encoded-week",
973
+ "name": "dateCellScheduleEncodedWeek",
974
+ "kind": "function",
975
+ "category": "date",
976
+ "module": "@dereekb/date",
977
+ "subpath": "date/date.cell.schedule",
978
+ "signature": "dateCellScheduleEncodedWeek(codes: Iterable<DateCellScheduleDayCode>): DateCellScheduleEncodedWeek",
979
+ "description": "Creates a simplified {@link DateCellScheduleEncodedWeek} from an iterable of {@link DateCellScheduleDayCode} values.\n\nCodes are passed through {@link simplifyDateCellScheduleDayCodes} so redundant individual day codes are collapsed\ninto shorthand (e.g. Mon-Fri becomes WEEKDAY `8`, Sat+Sun becomes WEEKEND `9`) and digits are emitted in ascending order.",
980
+ "params": [
981
+ {
982
+ "name": "codes",
983
+ "type": "Iterable<DateCellScheduleDayCode>",
984
+ "description": "- Day codes to encode into the compact string representation.",
985
+ "optional": false
986
+ }
987
+ ],
988
+ "returns": "The encoded week string.",
989
+ "tags": [
990
+ "date",
991
+ "schedule",
992
+ "encoded",
993
+ "week",
994
+ "encode",
995
+ "days",
996
+ "simplify",
997
+ "weekday",
998
+ "weekend",
999
+ "cell",
1000
+ "datecellscheduleencodedweek"
1001
+ ],
1002
+ "example": "// Encode weekdays only — collapses into the WEEKDAY shorthand\ndateCellScheduleEncodedWeek([DateCellScheduleDayCode.MONDAY, DateCellScheduleDayCode.TUESDAY, DateCellScheduleDayCode.WEDNESDAY, DateCellScheduleDayCode.THURSDAY, DateCellScheduleDayCode.FRIDAY]);\n// Returns '8'\n\n// Encode specific days\ndateCellScheduleEncodedWeek([DateCellScheduleDayCode.MONDAY, DateCellScheduleDayCode.WEDNESDAY]);\n// Returns '24'\n\n// Encode the full week\ndateCellScheduleEncodedWeek([DateCellScheduleDayCode.WEEKDAY, DateCellScheduleDayCode.WEEKEND]);\n// Returns '89'",
1003
+ "relatedSlugs": [
1004
+ "is-date-cell-schedule-encoded-week",
1005
+ "simplify-date-cell-schedule-day-codes",
1006
+ "expand-date-cell-schedule-day-codes"
1007
+ ]
1008
+ },
869
1009
  {
870
1010
  "slug": "time-duration-data-is-empty",
871
1011
  "name": "timeDurationDataIsEmpty",
@@ -1928,6 +1928,170 @@
1928
1928
  "example": "<dbx-bar>\n <span>Title</span>\n <dbx-spacer></dbx-spacer>\n <button mat-button>Action</button>\n</dbx-bar>",
1929
1929
  "minimalExample": "<dbx-spacer></dbx-spacer>"
1930
1930
  },
1931
+ {
1932
+ "slug": "style-body",
1933
+ "category": "layout",
1934
+ "kind": "directive",
1935
+ "selector": "[dbxStyleBody]",
1936
+ "className": "DbxStyleBodyDirective",
1937
+ "module": "@dereekb/dbx-web",
1938
+ "description": "Applies the current application style class from {@link DbxStyleService} to the document `<body>` element.\n\nPlace this directive on a root-level element so that the body tag receives the active style class.",
1939
+ "inputs": [],
1940
+ "outputs": [],
1941
+ "relatedSlugs": [
1942
+ "style",
1943
+ "style-service",
1944
+ "set-style"
1945
+ ],
1946
+ "example": "<div dbxStyleBody></div>",
1947
+ "minimalExample": "<div dbxStyleBody></div>"
1948
+ },
1949
+ {
1950
+ "slug": "color",
1951
+ "category": "layout",
1952
+ "kind": "directive",
1953
+ "selector": "[dbxColor]",
1954
+ "className": "DbxColorDirective",
1955
+ "module": "@dereekb/dbx-web",
1956
+ "description": "Applies a themed background color to the host element.\n\nAccepts either a {@link DbxThemeColor} string (e.g. `'primary'`, `'success'`) or a {@link DbxColorConfig}\nobject carrying arbitrary CSS color values (any hex, `rgb()`, `hsl()`, `var(...)`, `color-mix(...)`, etc.).\n\nOptionally set {@link dbxColorTone} (0-100) to control background opacity for a tonal/muted appearance.\nWhen tonal mode is active, the `dbx-color-tonal` CSS class is added and a CSS rule overrides the text\ncolor to the vibrant color (via `--dbx-bg-color-current`).\n\nThe standalone `[dbxColorTone]` input wins over `config.tone` when both are set; the same precedence\napplies to tonal mode.",
1957
+ "inputs": [
1958
+ {
1959
+ "name": "dbxColor",
1960
+ "type": "Maybe<DbxColorInput>",
1961
+ "description": "",
1962
+ "required": false
1963
+ },
1964
+ {
1965
+ "name": "dbxColorTone",
1966
+ "type": "Maybe<DbxColorTone>",
1967
+ "description": "Background tone level (0-100). When set, the background becomes semi-transparent\nand text color switches to the vibrant theme color for a tonal appearance.",
1968
+ "required": false
1969
+ }
1970
+ ],
1971
+ "outputs": [],
1972
+ "relatedSlugs": [
1973
+ "text-color",
1974
+ "color-service"
1975
+ ],
1976
+ "example": "<div [dbxColor]=\"'primary'\">Themed background</div>\n<div [dbxColor]=\"'primary'\" [dbxColorTone]=\"18\">Tonal themed</div>\n<div [dbxColor]=\"{ color: '#ff0066', contrast: 'white' }\">Custom hex</div>\n<div [dbxColor]=\"{ color: 'var(--mat-sys-tertiary)', contrast: 'var(--mat-sys-on-tertiary)', tone: 18 }\">Custom tonal</div>",
1977
+ "minimalExample": "<div [dbxColor]=\"'primary'\"></div>"
1978
+ },
1979
+ {
1980
+ "slug": "color-service",
1981
+ "category": "layout",
1982
+ "kind": "service",
1983
+ "selector": "",
1984
+ "className": "DbxColorService",
1985
+ "module": "@dereekb/dbx-web",
1986
+ "description": "Service that registers named {@link DbxColorConfigTemplate} entries and expands\n{@link DbxColorConfig} values that reference a template by key.\n\nSeeded via `provideDbxStyleService({ dbxColorServiceConfig: { templates: [...] } })`,\nthen injected by {@link DbxColorDirective} and {@link DbxTextColorDirective} to resolve\ntemplate references at render time.",
1987
+ "inputs": [],
1988
+ "outputs": [],
1989
+ "relatedSlugs": [
1990
+ "color",
1991
+ "text-color",
1992
+ "style-service"
1993
+ ],
1994
+ "example": "const colorService = inject(DbxColorService);\ncolorService.register({ key: 'brand-positive', config: { color: '#1f9b59', contrast: 'white', tone: 18 } });\ncolorService.expandColorConfig({ template: 'brand-positive' });\n// -> { template: 'brand-positive', color: '#1f9b59', contrast: 'white', tone: 18 }"
1995
+ },
1996
+ {
1997
+ "slug": "style",
1998
+ "category": "layout",
1999
+ "kind": "directive",
2000
+ "selector": "dbx-style, [dbxStyle], .dbx-style",
2001
+ "className": "DbxStyleDirective",
2002
+ "module": "@dereekb/dbx-web",
2003
+ "description": "Applies the current application style class from {@link DbxStyleService} to the host element.\n\nUse this directive to propagate the active style class onto any element or component.",
2004
+ "inputs": [],
2005
+ "outputs": [],
2006
+ "relatedSlugs": [
2007
+ "style-service",
2008
+ "style-body",
2009
+ "set-style"
2010
+ ],
2011
+ "example": "<div dbxStyle>Styled content</div>",
2012
+ "minimalExample": "<div dbxStyle></div>"
2013
+ },
2014
+ {
2015
+ "slug": "style-service",
2016
+ "category": "layout",
2017
+ "kind": "service",
2018
+ "selector": "",
2019
+ "className": "DbxStyleService",
2020
+ "module": "@dereekb/dbx-web",
2021
+ "description": "Manages application-wide style classes and suffix modes (e.g., dark mode).\n\nConsumers can set a default style config, override it with an observable config,\nand toggle style suffixes to switch between style variants at runtime.\n\nProvided via `provideDbxStyleService()` from `style.providers`.",
2022
+ "inputs": [],
2023
+ "outputs": [],
2024
+ "relatedSlugs": [
2025
+ "style",
2026
+ "set-style",
2027
+ "style-body",
2028
+ "color-service"
2029
+ ],
2030
+ "example": "const styleService = inject(DbxStyleService);\nstyleService.toggleDarkSuffix(); // toggle dark mode on/off\nstyleService.setStyleClassSuffix('dark'); // force dark mode"
2031
+ },
2032
+ {
2033
+ "slug": "set-style",
2034
+ "category": "layout",
2035
+ "kind": "directive",
2036
+ "selector": "[dbxSetStyle]",
2037
+ "className": "DbxSetStyleDirective",
2038
+ "module": "@dereekb/dbx-web",
2039
+ "description": "Sets the active application style for child elements and/or the global {@link DbxStyleService}.\n\nAccepts a {@link DbxStyleName} and optional suffixes, then applies the computed style class\ndepending on the configured {@link DbxSetStyleMode}.",
2040
+ "inputs": [
2041
+ {
2042
+ "name": "setStyleMode",
2043
+ "type": "DbxSetStyleMode",
2044
+ "description": "The mode for the style.\n\n- global: The style will be set on the parent DbxStyleService.\n- self: The style will be applied to the host element.",
2045
+ "required": false,
2046
+ "default": "'self'"
2047
+ },
2048
+ {
2049
+ "name": "dbxSetStyle",
2050
+ "type": "DbxStyleName",
2051
+ "description": "The input DbxStyleName to style the host element with.",
2052
+ "required": false
2053
+ },
2054
+ {
2055
+ "name": "suffixes",
2056
+ "type": "Maybe<string>",
2057
+ "description": "The input suffixes to allow to be applied to the",
2058
+ "required": false,
2059
+ "default": "undefined"
2060
+ }
2061
+ ],
2062
+ "outputs": [],
2063
+ "relatedSlugs": [
2064
+ "style",
2065
+ "style-service",
2066
+ "style-body"
2067
+ ],
2068
+ "example": "<div [dbxSetStyle]=\"'my-app'\" [setStyleMode]=\"'both'\" [suffixes]=\"'dark'\">\n <!-- Children inherit 'my-app' or 'my-app-dark' styling -->\n</div>",
2069
+ "minimalExample": "<div [dbxSetStyle]=\"'my-app'\"></div>"
2070
+ },
2071
+ {
2072
+ "slug": "text-color",
2073
+ "category": "layout",
2074
+ "kind": "directive",
2075
+ "selector": "[dbxTextColor]",
2076
+ "className": "DbxTextColorDirective",
2077
+ "module": "@dereekb/dbx-web",
2078
+ "description": "Applies a themed text color to the host element.\n\nAccepts either a {@link DbxThemeColor} string (e.g. `'primary'`, `'warn'`) or a {@link DbxColorConfig}\nobject carrying an arbitrary CSS color value. Unlike {@link DbxColorDirective} which sets the background,\nthis directive only sets the foreground text color.",
2079
+ "inputs": [
2080
+ {
2081
+ "name": "dbxTextColor",
2082
+ "type": "Maybe<DbxColorInput>",
2083
+ "description": "",
2084
+ "required": false
2085
+ }
2086
+ ],
2087
+ "outputs": [],
2088
+ "relatedSlugs": [
2089
+ "color",
2090
+ "color-service"
2091
+ ],
2092
+ "example": "<mat-icon [dbxTextColor]=\"'warn'\">error</mat-icon>\n<span [dbxTextColor]=\"'primary'\">Themed text</span>\n<span [dbxTextColor]=\"{ color: '#0066ff' }\">Custom hex text</span>",
2093
+ "minimalExample": "<span [dbxTextColor]=\"'primary'\"></span>"
2094
+ },
1931
2095
  {
1932
2096
  "slug": "click-to-copy-text",
1933
2097
  "category": "text",
@@ -264,7 +264,7 @@
264
264
  "whatItFlags": "A composite index required by tagged factories is missing from the committed `firestore.indexes.json`.",
265
265
  "whenItApplies": "Every entry in the generated composite set that has no equal entry in the committed JSON.",
266
266
  "whenItDoesNotApply": "Factories tagged `@dbxModelFirebaseIndexManual` — their shapes are author-managed and excluded from drift.",
267
- "canonicalFix": "Run the `scan-model-firebase-indexes` / `generate-firestore-indexes` CLIs and commit the regenerated `firestore.indexes.json`."
267
+ "canonicalFix": "Run `dbx-cli-generate-firestore-indexes --component <dir>` (and the `scan-model-firebase-indexes` CLI if the manifest is also stale) and commit the regenerated `firestore.indexes.json`."
268
268
  },
269
269
  {
270
270
  "code": "MODEL_FIREBASE_INDEX_COMPOSITE_REMOVED",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dereekb/dbx-components-mcp",
3
- "version": "13.11.15",
3
+ "version": "13.11.16",
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.11.15",
19
- "@dereekb/dbx-core": "13.11.15",
20
- "@dereekb/dbx-firebase": "13.11.15",
21
- "@dereekb/dbx-form": "13.11.15",
22
- "@dereekb/dbx-web": "13.11.15",
23
- "@dereekb/firebase": "13.11.15",
24
- "@dereekb/firebase-server": "13.11.15",
25
- "@dereekb/rxjs": "13.11.15",
26
- "@dereekb/util": "13.11.15",
18
+ "@dereekb/dbx-cli": "13.11.16",
19
+ "@dereekb/dbx-core": "13.11.16",
20
+ "@dereekb/dbx-firebase": "13.11.16",
21
+ "@dereekb/dbx-form": "13.11.16",
22
+ "@dereekb/dbx-web": "13.11.16",
23
+ "@dereekb/firebase": "13.11.16",
24
+ "@dereekb/firebase-server": "13.11.16",
25
+ "@dereekb/rxjs": "13.11.16",
26
+ "@dereekb/util": "13.11.16",
27
27
  "@uirouter/angular": "21.0.0",
28
28
  "rxjs": "^7.8.2"
29
29
  },
30
30
  "devDependencies": {
31
- "@dereekb/model": "13.11.15"
31
+ "@dereekb/model": "13.11.16"
32
32
  }
33
33
  }