@typicalday/firegraph 0.2.0 → 0.4.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.
package/dist/index.js CHANGED
@@ -773,6 +773,9 @@ function matchSegments(path, pi, pattern, qi) {
773
773
  function tripleKey(aType, axbType, bType) {
774
774
  return `${aType}:${axbType}:${bType}`;
775
775
  }
776
+ function tripleKeyFor(e) {
777
+ return tripleKey(e.aType, e.axbType, e.bType);
778
+ }
776
779
  function createRegistry(input) {
777
780
  const map = /* @__PURE__ */ new Map();
778
781
  let entries;
@@ -783,14 +786,35 @@ function createRegistry(input) {
783
786
  }
784
787
  const entryList = Object.freeze([...entries]);
785
788
  for (const entry of entries) {
789
+ if (entry.targetGraph && entry.targetGraph.includes("/")) {
790
+ throw new ValidationError(
791
+ `Entry (${entry.aType}) -[${entry.axbType}]-> (${entry.bType}) has invalid targetGraph "${entry.targetGraph}" \u2014 must be a single segment (no "/")`
792
+ );
793
+ }
786
794
  const key = tripleKey(entry.aType, entry.axbType, entry.bType);
787
795
  const validator = entry.jsonSchema ? compileSchema(entry.jsonSchema, `(${entry.aType}) -[${entry.axbType}]-> (${entry.bType})`) : void 0;
788
796
  map.set(key, { entry, validate: validator });
789
797
  }
798
+ const axbIndex = /* @__PURE__ */ new Map();
799
+ const axbBuild = /* @__PURE__ */ new Map();
800
+ for (const entry of entries) {
801
+ const existing = axbBuild.get(entry.axbType);
802
+ if (existing) {
803
+ existing.push(entry);
804
+ } else {
805
+ axbBuild.set(entry.axbType, [entry]);
806
+ }
807
+ }
808
+ for (const [key, arr] of axbBuild) {
809
+ axbIndex.set(key, Object.freeze(arr));
810
+ }
790
811
  return {
791
812
  lookup(aType, axbType, bType) {
792
813
  return map.get(tripleKey(aType, axbType, bType))?.entry;
793
814
  },
815
+ lookupByAxbType(axbType) {
816
+ return axbIndex.get(axbType) ?? [];
817
+ },
794
818
  validate(aType, axbType, bType, data, scopePath) {
795
819
  const rec = map.get(tripleKey(aType, axbType, bType));
796
820
  if (!rec) {
@@ -818,6 +842,45 @@ function createRegistry(input) {
818
842
  }
819
843
  };
820
844
  }
845
+ function createMergedRegistry(base, extension) {
846
+ const baseKeys = new Set(base.entries().map(tripleKeyFor));
847
+ return {
848
+ lookup(aType, axbType, bType) {
849
+ return base.lookup(aType, axbType, bType) ?? extension.lookup(aType, axbType, bType);
850
+ },
851
+ lookupByAxbType(axbType) {
852
+ const baseResults = base.lookupByAxbType(axbType);
853
+ const extResults = extension.lookupByAxbType(axbType);
854
+ if (extResults.length === 0) return baseResults;
855
+ if (baseResults.length === 0) return extResults;
856
+ const seen = new Set(baseResults.map(tripleKeyFor));
857
+ const merged = [...baseResults];
858
+ for (const entry of extResults) {
859
+ if (!seen.has(tripleKeyFor(entry))) {
860
+ merged.push(entry);
861
+ }
862
+ }
863
+ return Object.freeze(merged);
864
+ },
865
+ validate(aType, axbType, bType, data, scopePath) {
866
+ if (baseKeys.has(tripleKey(aType, axbType, bType))) {
867
+ return base.validate(aType, axbType, bType, data, scopePath);
868
+ }
869
+ return extension.validate(aType, axbType, bType, data, scopePath);
870
+ },
871
+ entries() {
872
+ const extEntries = extension.entries();
873
+ if (extEntries.length === 0) return base.entries();
874
+ const merged = [...base.entries()];
875
+ for (const entry of extEntries) {
876
+ if (!baseKeys.has(tripleKeyFor(entry))) {
877
+ merged.push(entry);
878
+ }
879
+ }
880
+ return Object.freeze(merged);
881
+ }
882
+ };
883
+ }
821
884
  function discoveryToEntries(discovery) {
822
885
  const entries = [];
823
886
  for (const [name, entity] of discovery.nodes) {
@@ -837,6 +900,12 @@ function discoveryToEntries(discovery) {
837
900
  if (!topology) continue;
838
901
  const fromTypes = Array.isArray(topology.from) ? topology.from : [topology.from];
839
902
  const toTypes = Array.isArray(topology.to) ? topology.to : [topology.to];
903
+ const resolvedTargetGraph = entity.targetGraph ?? topology.targetGraph;
904
+ if (resolvedTargetGraph && resolvedTargetGraph.includes("/")) {
905
+ throw new ValidationError(
906
+ `Edge "${axbType}" has invalid targetGraph "${resolvedTargetGraph}" \u2014 must be a single segment (no "/")`
907
+ );
908
+ }
840
909
  for (const aType of fromTypes) {
841
910
  for (const bType of toTypes) {
842
911
  entries.push({
@@ -848,7 +917,8 @@ function discoveryToEntries(discovery) {
848
917
  inverseLabel: topology.inverseLabel,
849
918
  titleField: entity.titleField,
850
919
  subtitleField: entity.subtitleField,
851
- allowedIn: entity.allowedIn
920
+ allowedIn: entity.allowedIn,
921
+ targetGraph: resolvedTargetGraph
852
922
  });
853
923
  }
854
924
  }
@@ -898,7 +968,8 @@ var EDGE_TYPE_SCHEMA = {
898
968
  subtitleField: { type: "string" },
899
969
  viewTemplate: { type: "string" },
900
970
  viewCss: { type: "string" },
901
- allowedIn: { type: "array", items: { type: "string", minLength: 1 } }
971
+ allowedIn: { type: "array", items: { type: "string", minLength: 1 } },
972
+ targetGraph: { type: "string", minLength: 1, pattern: "^[^/]+$" }
902
973
  },
903
974
  additionalProperties: false
904
975
  };
@@ -959,7 +1030,8 @@ async function createRegistryFromGraph(reader) {
959
1030
  inverseLabel: data.inverseLabel,
960
1031
  titleField: data.titleField,
961
1032
  subtitleField: data.subtitleField,
962
- allowedIn: data.allowedIn
1033
+ allowedIn: data.allowedIn,
1034
+ targetGraph: data.targetGraph
963
1035
  });
964
1036
  }
965
1037
  }
@@ -975,14 +1047,12 @@ var GraphClientImpl = class _GraphClientImpl {
975
1047
  this.db = db;
976
1048
  this.scopePath = scopePath;
977
1049
  this.adapter = createFirestoreAdapter(db, collectionPath);
978
- if (options?.registry && options?.registryMode) {
979
- throw new DynamicRegistryError(
980
- 'Cannot provide both "registry" and "registryMode". Use "registry" for static mode or "registryMode" for dynamic mode.'
981
- );
982
- }
983
1050
  if (options?.registryMode) {
984
1051
  this.dynamicConfig = options.registryMode;
985
1052
  this.bootstrapRegistry = createBootstrapRegistry();
1053
+ if (options.registry) {
1054
+ this.staticRegistry = options.registry;
1055
+ }
986
1056
  const metaCollectionPath = options.registryMode.collection;
987
1057
  if (metaCollectionPath && metaCollectionPath !== collectionPath) {
988
1058
  this.metaAdapter = createFirestoreAdapter(db, metaCollectionPath);
@@ -1034,18 +1104,20 @@ var GraphClientImpl = class _GraphClientImpl {
1034
1104
  /**
1035
1105
  * Get the appropriate registry for validating a write to the given type.
1036
1106
  *
1037
- * - Static mode: returns staticRegistry (or undefined if none set)
1038
- * - Dynamic mode:
1107
+ * - Static-only mode: returns staticRegistry (or undefined if none set)
1108
+ * - Dynamic mode (pure or merged):
1039
1109
  * - Meta-types (nodeType, edgeType): validated against bootstrapRegistry
1040
1110
  * - Domain types: validated against dynamicRegistry (falls back to
1041
1111
  * bootstrapRegistry which rejects unknown types)
1112
+ * - Merged mode: dynamicRegistry is a merged wrapper (static + dynamic
1113
+ * extension), so static entries take priority automatically.
1042
1114
  */
1043
1115
  getRegistryForType(aType) {
1044
1116
  if (!this.dynamicConfig) return this.staticRegistry;
1045
1117
  if (aType === META_NODE_TYPE || aType === META_EDGE_TYPE) {
1046
1118
  return this.bootstrapRegistry;
1047
1119
  }
1048
- return this.dynamicRegistry ?? this.bootstrapRegistry;
1120
+ return this.dynamicRegistry ?? this.staticRegistry ?? this.bootstrapRegistry;
1049
1121
  }
1050
1122
  /**
1051
1123
  * Get the Firestore adapter for writing the given type.
@@ -1059,13 +1131,13 @@ var GraphClientImpl = class _GraphClientImpl {
1059
1131
  }
1060
1132
  /**
1061
1133
  * Get the combined registry for transaction/batch context.
1062
- * In static mode, returns staticRegistry.
1134
+ * In static-only mode, returns staticRegistry.
1063
1135
  * In dynamic mode, returns dynamicRegistry (which includes bootstrap entries)
1064
- * or bootstrapRegistry if not yet reloaded.
1136
+ * or falls back to staticRegistry (merged mode) or bootstrapRegistry.
1065
1137
  */
1066
1138
  getCombinedRegistry() {
1067
1139
  if (!this.dynamicConfig) return this.staticRegistry;
1068
- return this.dynamicRegistry ?? this.bootstrapRegistry;
1140
+ return this.dynamicRegistry ?? this.staticRegistry ?? this.bootstrapRegistry;
1069
1141
  }
1070
1142
  // ---------------------------------------------------------------------------
1071
1143
  // Query dispatch
@@ -1213,6 +1285,33 @@ var GraphClientImpl = class _GraphClientImpl {
1213
1285
  );
1214
1286
  }
1215
1287
  // ---------------------------------------------------------------------------
1288
+ // Collection group query
1289
+ // ---------------------------------------------------------------------------
1290
+ async findEdgesGlobal(params, collectionName) {
1291
+ const name = collectionName ?? this.adapter.collectionPath.split("/").pop();
1292
+ const plan = buildEdgeQueryPlan(params);
1293
+ if (plan.strategy === "get") {
1294
+ throw new FiregraphError(
1295
+ "findEdgesGlobal() requires a query, not a direct document lookup. Omit one of aUid/axbType/bUid to force a query strategy.",
1296
+ "INVALID_QUERY"
1297
+ );
1298
+ }
1299
+ this.checkQuerySafety(plan.filters, params.allowCollectionScan);
1300
+ const collectionGroupRef = this.db.collectionGroup(name);
1301
+ let q = collectionGroupRef;
1302
+ for (const f of plan.filters) {
1303
+ q = q.where(f.field, f.op, f.value);
1304
+ }
1305
+ if (plan.options?.orderBy) {
1306
+ q = q.orderBy(plan.options.orderBy.field, plan.options.orderBy.direction ?? "asc");
1307
+ }
1308
+ if (plan.options?.limit !== void 0) {
1309
+ q = q.limit(plan.options.limit);
1310
+ }
1311
+ const snap = await q.get();
1312
+ return snap.docs.map((doc) => doc.data());
1313
+ }
1314
+ // ---------------------------------------------------------------------------
1216
1315
  // Bulk operations
1217
1316
  // ---------------------------------------------------------------------------
1218
1317
  async removeNodeCascade(uid, options) {
@@ -1235,6 +1334,11 @@ var GraphClientImpl = class _GraphClientImpl {
1235
1334
  `Cannot define type "${name}": this name is reserved for the meta-registry.`
1236
1335
  );
1237
1336
  }
1337
+ if (this.staticRegistry?.lookup(name, NODE_RELATION, name)) {
1338
+ throw new DynamicRegistryError(
1339
+ `Cannot define node type "${name}": already defined in the static registry.`
1340
+ );
1341
+ }
1238
1342
  const uid = generateDeterministicUid(META_NODE_TYPE, name);
1239
1343
  const data = { name, jsonSchema };
1240
1344
  if (description !== void 0) data.description = description;
@@ -1256,6 +1360,19 @@ var GraphClientImpl = class _GraphClientImpl {
1256
1360
  `Cannot define type "${name}": this name is reserved for the meta-registry.`
1257
1361
  );
1258
1362
  }
1363
+ if (this.staticRegistry) {
1364
+ const fromTypes = Array.isArray(topology.from) ? topology.from : [topology.from];
1365
+ const toTypes = Array.isArray(topology.to) ? topology.to : [topology.to];
1366
+ for (const aType of fromTypes) {
1367
+ for (const bType of toTypes) {
1368
+ if (this.staticRegistry.lookup(aType, name, bType)) {
1369
+ throw new DynamicRegistryError(
1370
+ `Cannot define edge type "${name}" for (${aType}) -> (${bType}): already defined in the static registry.`
1371
+ );
1372
+ }
1373
+ }
1374
+ }
1375
+ }
1259
1376
  const uid = generateDeterministicUid(META_EDGE_TYPE, name);
1260
1377
  const data = {
1261
1378
  name,
@@ -1264,6 +1381,7 @@ var GraphClientImpl = class _GraphClientImpl {
1264
1381
  };
1265
1382
  if (jsonSchema !== void 0) data.jsonSchema = jsonSchema;
1266
1383
  if (topology.inverseLabel !== void 0) data.inverseLabel = topology.inverseLabel;
1384
+ if (topology.targetGraph !== void 0) data.targetGraph = topology.targetGraph;
1267
1385
  if (description !== void 0) data.description = description;
1268
1386
  if (options?.titleField !== void 0) data.titleField = options.titleField;
1269
1387
  if (options?.subtitleField !== void 0) data.subtitleField = options.subtitleField;
@@ -1279,7 +1397,12 @@ var GraphClientImpl = class _GraphClientImpl {
1279
1397
  );
1280
1398
  }
1281
1399
  const reader = this.createMetaReader();
1282
- this.dynamicRegistry = await createRegistryFromGraph(reader);
1400
+ const dynamicOnly = await createRegistryFromGraph(reader);
1401
+ if (this.staticRegistry) {
1402
+ this.dynamicRegistry = createMergedRegistry(this.staticRegistry, dynamicOnly);
1403
+ } else {
1404
+ this.dynamicRegistry = dynamicOnly;
1405
+ }
1283
1406
  }
1284
1407
  /**
1285
1408
  * Create a GraphReader for the meta-collection.
@@ -1338,6 +1461,10 @@ function generateId() {
1338
1461
  var DEFAULT_LIMIT = 10;
1339
1462
  var DEFAULT_MAX_READS = 100;
1340
1463
  var DEFAULT_CONCURRENCY = 5;
1464
+ var _crossGraphWarned = false;
1465
+ function isGraphClient(reader) {
1466
+ return "subgraph" in reader && typeof reader.subgraph === "function";
1467
+ }
1341
1468
  var Semaphore = class {
1342
1469
  constructor(slots) {
1343
1470
  this.slots = slots;
@@ -1363,9 +1490,10 @@ var Semaphore = class {
1363
1490
  }
1364
1491
  };
1365
1492
  var TraversalBuilderImpl = class {
1366
- constructor(reader, startUid) {
1493
+ constructor(reader, startUid, registry) {
1367
1494
  this.reader = reader;
1368
1495
  this.startUid = startUid;
1496
+ this.registry = registry;
1369
1497
  }
1370
1498
  hops = [];
1371
1499
  follow(axbType, options) {
@@ -1382,11 +1510,13 @@ var TraversalBuilderImpl = class {
1382
1510
  const semaphore = new Semaphore(concurrency);
1383
1511
  let totalReads = 0;
1384
1512
  let truncated = false;
1385
- let sourceUids = [this.startUid];
1513
+ let sources = [
1514
+ { uid: this.startUid, reader: this.reader }
1515
+ ];
1386
1516
  const hopResults = [];
1387
1517
  for (let depth = 0; depth < this.hops.length; depth++) {
1388
1518
  const hop = this.hops[depth];
1389
- if (sourceUids.length === 0) {
1519
+ if (sources.length === 0) {
1390
1520
  hopResults.push({
1391
1521
  axbType: hop.axbType,
1392
1522
  depth,
@@ -1397,9 +1527,12 @@ var TraversalBuilderImpl = class {
1397
1527
  continue;
1398
1528
  }
1399
1529
  const hopEdges = [];
1400
- const sourceCount = sourceUids.length;
1530
+ const sourceCount = sources.length;
1401
1531
  let hopTruncated = false;
1402
- const tasks = sourceUids.map((uid) => async () => {
1532
+ const resolvedTargetGraph = this.resolveTargetGraph(hop);
1533
+ const direction = hop.direction ?? "forward";
1534
+ const isCrossGraph = direction === "forward" && !!resolvedTargetGraph;
1535
+ const tasks = sources.map(({ uid, reader: sourceReader }) => async () => {
1403
1536
  if (totalReads >= maxReads) {
1404
1537
  hopTruncated = true;
1405
1538
  return;
@@ -1411,19 +1544,18 @@ var TraversalBuilderImpl = class {
1411
1544
  return;
1412
1545
  }
1413
1546
  totalReads++;
1414
- const direction2 = hop.direction ?? "forward";
1415
1547
  const params = { axbType: hop.axbType };
1416
- if (direction2 === "forward") {
1548
+ if (direction === "forward") {
1417
1549
  params.aUid = uid;
1418
1550
  if (hop.bType) params.bType = hop.bType;
1419
1551
  } else {
1420
1552
  params.bUid = uid;
1421
1553
  if (hop.aType) params.aType = hop.aType;
1422
1554
  }
1423
- if (direction2 === "forward" && hop.aType) {
1555
+ if (direction === "forward" && hop.aType) {
1424
1556
  params.aType = hop.aType;
1425
1557
  }
1426
- if (direction2 === "reverse" && hop.bType) {
1558
+ if (direction === "reverse" && hop.bType) {
1427
1559
  params.bType = hop.bType;
1428
1560
  }
1429
1561
  if (hop.orderBy) params.orderBy = hop.orderBy;
@@ -1433,31 +1565,58 @@ var TraversalBuilderImpl = class {
1433
1565
  } else {
1434
1566
  params.limit = limit;
1435
1567
  }
1436
- let edges = await this.reader.findEdges(params);
1568
+ let hopReader;
1569
+ let nextReader;
1570
+ if (isCrossGraph) {
1571
+ if (isGraphClient(this.reader)) {
1572
+ hopReader = this.reader.subgraph(uid, resolvedTargetGraph);
1573
+ nextReader = hopReader;
1574
+ } else {
1575
+ hopReader = sourceReader;
1576
+ nextReader = sourceReader;
1577
+ if (!_crossGraphWarned) {
1578
+ _crossGraphWarned = true;
1579
+ console.warn(
1580
+ `[firegraph] Traversal hop "${hop.axbType}" has targetGraph "${resolvedTargetGraph}" but the reader does not support subgraph(). Cross-graph hop will query the current collection instead. Pass a GraphClient to createTraversal() to enable cross-graph traversal.`
1581
+ );
1582
+ }
1583
+ }
1584
+ } else {
1585
+ hopReader = sourceReader;
1586
+ nextReader = sourceReader;
1587
+ }
1588
+ let edges2 = await hopReader.findEdges(params);
1437
1589
  if (hop.filter) {
1438
- edges = edges.filter(hop.filter);
1439
- edges = edges.slice(0, limit);
1590
+ edges2 = edges2.filter(hop.filter);
1591
+ edges2 = edges2.slice(0, limit);
1592
+ }
1593
+ for (const edge of edges2) {
1594
+ hopEdges.push({ edge, reader: nextReader });
1440
1595
  }
1441
- hopEdges.push(...edges);
1442
1596
  } finally {
1443
1597
  semaphore.release();
1444
1598
  }
1445
1599
  });
1446
1600
  await Promise.all(tasks.map((task) => task()));
1601
+ const edges = hopEdges.map((h) => h.edge);
1447
1602
  hopResults.push({
1448
1603
  axbType: hop.axbType,
1449
1604
  depth,
1450
- edges: returnIntermediates ? [...hopEdges] : hopEdges,
1605
+ edges: returnIntermediates ? [...edges] : edges,
1451
1606
  sourceCount,
1452
1607
  truncated: hopTruncated
1453
1608
  });
1454
1609
  if (hopTruncated) {
1455
1610
  truncated = true;
1456
1611
  }
1457
- const direction = hop.direction ?? "forward";
1458
- sourceUids = [...new Set(
1459
- hopEdges.map((e) => direction === "forward" ? e.bUid : e.aUid)
1460
- )];
1612
+ const seen = /* @__PURE__ */ new Map();
1613
+ for (const { edge, reader: edgeReader } of hopEdges) {
1614
+ const nextUid = direction === "forward" ? edge.bUid : edge.aUid;
1615
+ if (!seen.has(nextUid)) {
1616
+ seen.set(nextUid, edgeReader);
1617
+ }
1618
+ }
1619
+ sources = [...seen.entries()].map(([uid, reader]) => ({ uid, reader }));
1461
1620
  }
1462
1621
  const lastHop = hopResults[hopResults.length - 1];
1463
1622
  return {
@@ -1467,9 +1626,25 @@ var TraversalBuilderImpl = class {
1467
1626
  truncated
1468
1627
  };
1469
1628
  }
1629
+ /**
1630
+ * Resolve the targetGraph for a hop. Priority:
1631
+ * 1. Explicit `hop.targetGraph` (user override)
1632
+ * 2. Registry `targetGraph` for the axbType (if registry available)
1633
+ * 3. undefined (no cross-graph)
1634
+ */
1635
+ resolveTargetGraph(hop) {
1636
+ if (hop.targetGraph) return hop.targetGraph;
1637
+ if (this.registry) {
1638
+ const entries = this.registry.lookupByAxbType(hop.axbType);
1639
+ for (const entry of entries) {
1640
+ if (entry.targetGraph) return entry.targetGraph;
1641
+ }
1642
+ }
1643
+ return void 0;
1644
+ }
1470
1645
  };
1471
- function createTraversal(reader, startUid) {
1472
- return new TraversalBuilderImpl(reader, startUid);
1646
+ function createTraversal(reader, startUid, registry) {
1647
+ return new TraversalBuilderImpl(reader, startUid, registry);
1473
1648
  }
1474
1649
 
1475
1650
  // src/views.ts
@@ -1717,7 +1892,8 @@ function loadEdgeEntity(dir, name) {
1717
1892
  viewDefaults: meta?.viewDefaults,
1718
1893
  viewsPath,
1719
1894
  sampleData,
1720
- allowedIn: meta?.allowedIn
1895
+ allowedIn: meta?.allowedIn,
1896
+ targetGraph: topology.targetGraph ?? meta?.targetGraph
1721
1897
  };
1722
1898
  }
1723
1899
  function getSubdirectories(dir) {
@@ -1760,6 +1936,20 @@ function discoverEntities(entitiesDir) {
1760
1936
  };
1761
1937
  }
1762
1938
 
1939
+ // src/cross-graph.ts
1940
+ function resolveAncestorCollection(collectionPath, uid) {
1941
+ const segments = collectionPath.split("/");
1942
+ for (let i = 1; i < segments.length; i += 2) {
1943
+ if (segments[i] === uid) {
1944
+ return segments.slice(0, i).join("/");
1945
+ }
1946
+ }
1947
+ return null;
1948
+ }
1949
+ function isAncestorUid(collectionPath, uid) {
1950
+ return resolveAncestorCollection(collectionPath, uid) !== null;
1951
+ }
1952
+
1763
1953
  // src/indexes.ts
1764
1954
  function baseIndexes(collection) {
1765
1955
  return [
@@ -1802,7 +1992,43 @@ function extractSchemaFields(schema) {
1802
1992
  if (s.type !== "object" || !s.properties) return [];
1803
1993
  return Object.keys(s.properties);
1804
1994
  }
1805
- function generateIndexConfig(collection, entities) {
1995
+ function collectionGroupIndexes(collectionName) {
1996
+ return [
1997
+ {
1998
+ collectionGroup: collectionName,
1999
+ queryScope: "COLLECTION_GROUP",
2000
+ fields: [
2001
+ { fieldPath: "aUid", order: "ASCENDING" },
2002
+ { fieldPath: "axbType", order: "ASCENDING" }
2003
+ ]
2004
+ },
2005
+ {
2006
+ collectionGroup: collectionName,
2007
+ queryScope: "COLLECTION_GROUP",
2008
+ fields: [
2009
+ { fieldPath: "axbType", order: "ASCENDING" },
2010
+ { fieldPath: "bUid", order: "ASCENDING" }
2011
+ ]
2012
+ },
2013
+ {
2014
+ collectionGroup: collectionName,
2015
+ queryScope: "COLLECTION_GROUP",
2016
+ fields: [
2017
+ { fieldPath: "aType", order: "ASCENDING" },
2018
+ { fieldPath: "axbType", order: "ASCENDING" }
2019
+ ]
2020
+ },
2021
+ {
2022
+ collectionGroup: collectionName,
2023
+ queryScope: "COLLECTION_GROUP",
2024
+ fields: [
2025
+ { fieldPath: "axbType", order: "ASCENDING" },
2026
+ { fieldPath: "bType", order: "ASCENDING" }
2027
+ ]
2028
+ }
2029
+ ];
2030
+ }
2031
+ function generateIndexConfig(collection, entities, registryEntries) {
1806
2032
  const indexes = baseIndexes(collection);
1807
2033
  if (entities) {
1808
2034
  for (const [, entity] of entities.nodes) {
@@ -1834,6 +2060,17 @@ function generateIndexConfig(collection, entities) {
1834
2060
  }
1835
2061
  }
1836
2062
  }
2063
+ if (registryEntries) {
2064
+ const targetGraphNames = /* @__PURE__ */ new Set();
2065
+ for (const entry of registryEntries) {
2066
+ if (entry.targetGraph) {
2067
+ targetGraphNames.add(entry.targetGraph);
2068
+ }
2069
+ }
2070
+ for (const name of targetGraphNames) {
2071
+ indexes.push(...collectionGroupIndexes(name));
2072
+ }
2073
+ }
1837
2074
  return { indexes, fieldOverrides: [] };
1838
2075
  }
1839
2076
  export {
@@ -1866,6 +2103,7 @@ export {
1866
2103
  computeNodeDocId,
1867
2104
  createBootstrapRegistry,
1868
2105
  createGraphClient,
2106
+ createMergedRegistry,
1869
2107
  createRegistry,
1870
2108
  createRegistryFromGraph,
1871
2109
  createTraversal,
@@ -1876,9 +2114,11 @@ export {
1876
2114
  generateId,
1877
2115
  generateIndexConfig,
1878
2116
  generateTypes,
2117
+ isAncestorUid,
1879
2118
  jsonSchemaToFieldMeta,
1880
2119
  matchScope,
1881
2120
  matchScopeAny,
2121
+ resolveAncestorCollection,
1882
2122
  resolveView
1883
2123
  };
1884
2124
  //# sourceMappingURL=index.js.map