@dereekb/dbx-components-mcp 14.5.1 → 14.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,7 +10,7 @@ var __export = (target, all) => {
10
10
  // packages/dbx-components-mcp/package.json
11
11
  var package_default = {
12
12
  name: "@dereekb/dbx-components-mcp",
13
- version: "14.5.1",
13
+ version: "14.6.0",
14
14
  sideEffects: false,
15
15
  type: "module",
16
16
  bin: {
@@ -22,8 +22,8 @@ var package_default = {
22
22
  "ts-morph": "^21.0.0"
23
23
  },
24
24
  peerDependencies: {
25
- "@dereekb/dbx-cli": "14.5.1",
26
- "@dereekb/util": "14.5.1"
25
+ "@dereekb/dbx-cli": "14.6.0",
26
+ "@dereekb/util": "14.6.0"
27
27
  }
28
28
  };
29
29
 
@@ -2337,6 +2337,10 @@ var FIREBASE_MODELS = [
2337
2337
  description: "Root notification container for a model. The document ID is the two-way flat key of the model it represents (see {@link notificationBoxIdForModel} in `notification.id.ts`).",
2338
2338
  modelGroup: "Notification",
2339
2339
  collectionKind: "root",
2340
+ compositeKey: {
2341
+ from: "*",
2342
+ encoding: "two-way"
2343
+ },
2340
2344
  archetypes: ["composite-key-root"]
2341
2345
  },
2342
2346
  {
@@ -2417,6 +2421,10 @@ var FIREBASE_MODELS = [
2417
2421
  description: "Aggregated notification feed for a specific model. Holds embedded {@link NotificationItem} entries that summarize recent notifications, similar to an activity feed.",
2418
2422
  modelGroup: "Notification",
2419
2423
  collectionKind: "root",
2424
+ compositeKey: {
2425
+ from: "*",
2426
+ encoding: "two-way"
2427
+ },
2420
2428
  archetypes: ["root-singleton-aggregate", "composite-key-root"]
2421
2429
  },
2422
2430
  {
@@ -29467,6 +29475,7 @@ var SERVICE_FACTORY_TAG = "dbxModelServiceFactory";
29467
29475
  var MCP_TOOL_NAME_SEGMENT_TAG = "dbxModelMcpToolNameSegment";
29468
29476
  var MODEL_TYPE_VALUE_PATTERN2 = /^[a-z][A-Za-z0-9_$]*$/;
29469
29477
  var TOOL_NAME_SEGMENT_PATTERN = /^[A-Za-z][A-Za-z0-9_$]*$/;
29478
+ var COMPOSITE_KEY_MODEL_NAME_PATTERN = /^[A-Za-z][A-Za-z0-9_$]*$/;
29470
29479
  var IDENTITY_FN = "firestoreModelIdentity";
29471
29480
  var IDENTITY_TYPE = "FirestoreModelIdentity";
29472
29481
  var ROOT_IDENTITY_TYPE = "RootFirestoreModelIdentity";
@@ -29583,6 +29592,7 @@ function buildInterface2(decl) {
29583
29592
  const dbxModelRead = readDbxModelReadTag(jsDocs);
29584
29593
  const dbxModelServerOnly = jsDocsHaveTag(jsDocs, "dbxModelServerOnly");
29585
29594
  const mcpToolNameSegment = readMcpToolNameSegmentTag(jsDocs);
29595
+ const compositeKey2 = readDbxModelCompositeKeyTag2(jsDocs);
29586
29596
  const extendsNames = decl.getExtends().map(resolveExtendsName);
29587
29597
  const props = [];
29588
29598
  for (const prop of decl.getProperties()) {
@@ -29608,7 +29618,8 @@ function buildInterface2(decl) {
29608
29618
  props,
29609
29619
  ...dbxModelRead === void 0 ? {} : { dbxModelRead },
29610
29620
  ...dbxModelServerOnly ? { dbxModelServerOnly: true } : {},
29611
- ...mcpToolNameSegment === void 0 ? {} : { mcpToolNameSegment }
29621
+ ...mcpToolNameSegment === void 0 ? {} : { mcpToolNameSegment },
29622
+ ...compositeKey2 === void 0 ? {} : { compositeKey: compositeKey2 }
29612
29623
  };
29613
29624
  }
29614
29625
  function readMcpToolNameSegmentTag(jsDocs) {
@@ -29643,6 +29654,43 @@ function readDbxModelReadTag(jsDocs) {
29643
29654
  }
29644
29655
  return result;
29645
29656
  }
29657
+ function readDbxModelCompositeKeyTag2(jsDocs) {
29658
+ let result;
29659
+ for (const doc of jsDocs) {
29660
+ for (const tag of doc.getTags()) {
29661
+ if (tag.getTagName() !== "dbxModelCompositeKey") continue;
29662
+ if (result !== void 0) continue;
29663
+ result = parseCompositeKeyTagValue2(tag.getCommentText() ?? "");
29664
+ }
29665
+ }
29666
+ return result;
29667
+ }
29668
+ function parseCompositeKeyTagValue2(raw) {
29669
+ let from;
29670
+ let encoding;
29671
+ for (const token of raw.trim().split(/\s+/)) {
29672
+ const eq = token.indexOf("=");
29673
+ if (eq <= 0) continue;
29674
+ const key = token.slice(0, eq);
29675
+ const value = token.slice(eq + 1);
29676
+ if (key === "from") {
29677
+ from = parseCompositeKeyFromValue3(value);
29678
+ } else if (key === "encoding" && (value === "one-way" || value === "two-way")) {
29679
+ encoding = value;
29680
+ }
29681
+ }
29682
+ return from !== void 0 && encoding !== void 0 ? { from, encoding } : void 0;
29683
+ }
29684
+ function parseCompositeKeyFromValue3(value) {
29685
+ let result;
29686
+ if (value === "*") {
29687
+ result = "*";
29688
+ } else {
29689
+ const names = value.split(",").map((x) => x.trim()).filter((x) => COMPOSITE_KEY_MODEL_NAME_PATTERN.test(x));
29690
+ result = names.length > 0 ? names : void 0;
29691
+ }
29692
+ return result;
29693
+ }
29646
29694
  function readServiceFactories(sourceFile) {
29647
29695
  const out = [];
29648
29696
  for (const statement of sourceFile.getVariableStatements()) {
@@ -40781,7 +40829,7 @@ var DBX_MODEL_DECODE_TOOL = {
40781
40829
  "",
40782
40830
  'Document mode \u2014 pass `data` as a JSON string (copied straight from the Firestore console) or an already-parsed object to identify the model, expand abbreviated field names, decode enum integer values, and surface foreign-key relationships. Optionally pass `model` to skip detection and target a specific model by interface name (`"StorageFile"`), identity constant (`"storageFileIdentity"`), `modelType` (`"storageFile"`), or collection prefix (`"sf"`).',
40783
40831
  "",
40784
- 'Key mode \u2014 pass just `key` (e.g. `"jwr/hkzQa9W6MpaP99RTlQJcImbWdZm2"`) to resolve the model identity and id from the collection prefix alone, no document required. Subcollection paths like `"nb/abc/nbn/def"` are walked end-to-end so the leaf model is reported alongside its parent chain.',
40832
+ 'Key mode \u2014 pass just `key` (e.g. `"jwr/hkzQa9W6MpaP99RTlQJcImbWdZm2"`) to resolve the model identity and id from the collection prefix alone, no document required. Subcollection paths like `"nb/abc/nbn/def"` are walked end-to-end so the leaf model is reported alongside its parent chain. Composite-key models derived from the key (`@dbxModelCompositeKey from=\u2026`) are listed with their ready-to-use flattened keys, and a two-way composite-key leaf reports the source key recovered from its id.',
40785
40833
  "",
40786
40834
  "At least one of `data` or `key` is required."
40787
40835
  ].join("\n"),
@@ -40905,6 +40953,29 @@ function buildPrefixMap() {
40905
40953
  }
40906
40954
  return out;
40907
40955
  }
40956
+ function findDerivedCompositeKeys(rawKey, leafModel) {
40957
+ const out = [];
40958
+ for (const model of FIREBASE_MODELS) {
40959
+ const compositeKey2 = model.compositeKey;
40960
+ if (!compositeKey2 || model.modelType === leafModel.modelType) continue;
40961
+ const matches = compositeKey2.from === "*" || compositeKey2.from.some((name) => name === leafModel.name || name === leafModel.identityConst || name === leafModel.modelType);
40962
+ if (!matches) continue;
40963
+ const flatId = compositeKey2.encoding === "two-way" ? rawKey.replaceAll("/", "_") : rawKey.replaceAll("/", "");
40964
+ out.push({ key: `${model.collectionPrefix}/${flatId}`, model, encoding: compositeKey2.encoding });
40965
+ }
40966
+ return out;
40967
+ }
40968
+ function decodeCompositeSource(leaf) {
40969
+ let result;
40970
+ if (leaf.model?.compositeKey?.encoding === "two-way" && leaf.id.includes("_")) {
40971
+ const sourceKey = leaf.id.replaceAll("_", "/");
40972
+ const decoded = decodeKeyPath(sourceKey, void 0);
40973
+ if (!("error" in decoded)) {
40974
+ result = { key: sourceKey, path: decoded };
40975
+ }
40976
+ }
40977
+ return result;
40978
+ }
40908
40979
  function decodeKeyPath(key, hint) {
40909
40980
  const trimmed = key.trim();
40910
40981
  if (trimmed.length === 0) {
@@ -40971,8 +41042,24 @@ function formatUnresolved(unresolvedPrefixes) {
40971
41042
  const list = unresolvedPrefixes.map((p) => `\`${p}\``).join(", ");
40972
41043
  return ["", `_Unresolved ${label}: ${list}. Run \`dbx_model_lookup\` to browse known models._`];
40973
41044
  }
41045
+ function formatCompositeSource(source) {
41046
+ if (!source) return [];
41047
+ const sourceModel = source.path.leaf.model ? source.path.leaf.model.name : `_unknown_ (prefix \`${source.path.leaf.prefix}\`)`;
41048
+ return ["", `**Composite source (two-way):** \`${source.key}\` \u2192 ${sourceModel}`];
41049
+ }
41050
+ function formatDerivedKeys(derived) {
41051
+ if (derived.length === 0) return [];
41052
+ const out = ["", "**Derived keys:**"];
41053
+ for (const entry of derived) {
41054
+ out.push(`- ${entry.model.name} (${entry.encoding}) \u2014 \`${entry.key}\``);
41055
+ }
41056
+ return out;
41057
+ }
40974
41058
  function formatKeyDecode(input, rawKey) {
40975
- const lines = ["_Model decoded from key prefix._", "", ...formatLeaf(input.leaf), ...formatAncestors(input.ancestors), ...formatUnresolved(input.unresolvedPrefixes), "", `_Key:_ \`${rawKey}\``];
41059
+ const trimmedKey = rawKey.trim();
41060
+ const derived = input.leaf.model ? findDerivedCompositeKeys(trimmedKey, input.leaf.model) : [];
41061
+ const compositeSource = decodeCompositeSource(input.leaf);
41062
+ const lines = ["_Model decoded from key prefix._", "", ...formatLeaf(input.leaf), ...formatAncestors(input.ancestors), ...formatUnresolved(input.unresolvedPrefixes), ...formatCompositeSource(compositeSource), ...formatDerivedKeys(derived), "", `_Key:_ \`${rawKey}\``];
40976
41063
  return lines.join("\n");
40977
41064
  }
40978
41065
  function runModelDecode(rawArgs) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dereekb/dbx-components-mcp",
3
- "version": "14.5.1",
3
+ "version": "14.6.0",
4
4
  "sideEffects": false,
5
5
  "type": "module",
6
6
  "bin": {
@@ -12,7 +12,7 @@
12
12
  "ts-morph": "^21.0.0"
13
13
  },
14
14
  "peerDependencies": {
15
- "@dereekb/dbx-cli": "14.5.1",
16
- "@dereekb/util": "14.5.1"
15
+ "@dereekb/dbx-cli": "14.6.0",
16
+ "@dereekb/util": "14.6.0"
17
17
  }
18
18
  }