@tinacms/graphql 0.0.0-d08af95-20241024210716 → 0.0.0-d1bd1a1-20251124051649

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
@@ -17,14 +17,18 @@ var __copyProps = (to, from, except, desc) => {
17
17
  return to;
18
18
  };
19
19
  var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
20
24
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
21
25
  mod
22
26
  ));
23
27
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
24
28
 
25
29
  // src/index.ts
26
- var src_exports = {};
27
- __export(src_exports, {
30
+ var index_exports = {};
31
+ __export(index_exports, {
28
32
  AuditFileSystemBridge: () => AuditFileSystemBridge,
29
33
  Database: () => Database,
30
34
  FilesystemBridge: () => FilesystemBridge,
@@ -58,11 +62,11 @@ __export(src_exports, {
58
62
  transformDocument: () => transformDocument,
59
63
  transformDocumentIntoPayload: () => transformDocumentIntoPayload
60
64
  });
61
- module.exports = __toCommonJS(src_exports);
65
+ module.exports = __toCommonJS(index_exports);
62
66
 
63
67
  // src/build.ts
64
68
  var import_graphql2 = require("graphql");
65
- var import_lodash3 = __toESM(require("lodash.uniqby"));
69
+ var import_es_toolkit3 = require("es-toolkit");
66
70
 
67
71
  // src/util.ts
68
72
  var yup = __toESM(require("yup"));
@@ -118,7 +122,7 @@ var flattenDeep = (arr) => arr.flatMap(
118
122
  );
119
123
 
120
124
  // src/ast-builder/index.ts
121
- var import_lodash = __toESM(require("lodash.uniqby"));
125
+ var import_es_toolkit = require("es-toolkit");
122
126
  var SysFieldDefinition = {
123
127
  kind: "Field",
124
128
  name: {
@@ -130,6 +134,15 @@ var SysFieldDefinition = {
130
134
  selectionSet: {
131
135
  kind: "SelectionSet",
132
136
  selections: [
137
+ // {
138
+ // kind: 'Field' as const,
139
+ // name: {
140
+ // kind: 'Name' as const,
141
+ // value: 'title',
142
+ // },
143
+ // arguments: [],
144
+ // directives: [],
145
+ // },
133
146
  {
134
147
  kind: "Field",
135
148
  name: {
@@ -148,6 +161,15 @@ var SysFieldDefinition = {
148
161
  arguments: [],
149
162
  directives: []
150
163
  },
164
+ {
165
+ kind: "Field",
166
+ name: {
167
+ kind: "Name",
168
+ value: "hasReferences"
169
+ },
170
+ arguments: [],
171
+ directives: []
172
+ },
151
173
  {
152
174
  kind: "Field",
153
175
  name: {
@@ -188,6 +210,10 @@ var SysFieldDefinition = {
188
210
  }
189
211
  };
190
212
  var astBuilder = {
213
+ /**
214
+ * `FormFieldBuilder` acts as a shortcut to building an entire `ObjectTypeDefinition`, we use this
215
+ * because all Tina field objects share a common set of fields ('name', 'label', 'component')
216
+ */
191
217
  FormFieldBuilder: ({
192
218
  name,
193
219
  additionalFields
@@ -411,6 +437,8 @@ var astBuilder = {
411
437
  kind: "Name",
412
438
  value: name
413
439
  },
440
+ // @ts-ignore FIXME; this is being handled properly but we're lying to
441
+ // ts and then fixing it in the `extractInlineTypes` function
414
442
  fields
415
443
  }),
416
444
  UnionTypeDefinition: ({
@@ -423,6 +451,8 @@ var astBuilder = {
423
451
  value: name
424
452
  },
425
453
  directives: [],
454
+ // @ts-ignore FIXME; this is being handled properly but we're lying to
455
+ // ts and then fixing it in the `extractInlineTypes` function
426
456
  types: types.map((name2) => ({
427
457
  kind: "NamedType",
428
458
  name: {
@@ -519,8 +549,11 @@ var astBuilder = {
519
549
  string: "String",
520
550
  boolean: "Boolean",
521
551
  number: "Float",
552
+ // FIXME - needs to be float or int
522
553
  datetime: "String",
554
+ // FIXME
523
555
  image: "String",
556
+ // FIXME
524
557
  text: "String"
525
558
  };
526
559
  return scalars[type];
@@ -1004,12 +1037,13 @@ var astBuilder = {
1004
1037
  };
1005
1038
  },
1006
1039
  toGraphQLAst: (ast) => {
1007
- const definitions = (0, import_lodash.default)(
1040
+ const definitions = (0, import_es_toolkit.uniqBy)(
1008
1041
  [
1009
1042
  ...extractInlineTypes(ast.query),
1010
1043
  ...extractInlineTypes(ast.globalTemplates),
1011
1044
  ...ast.definitions
1012
1045
  ],
1046
+ // @ts-ignore - all nodes have a name property in practice
1013
1047
  (field) => field.name.value
1014
1048
  );
1015
1049
  return {
@@ -1019,8 +1053,7 @@ var astBuilder = {
1019
1053
  }
1020
1054
  };
1021
1055
  var capitalize = (s) => {
1022
- if (typeof s !== "string")
1023
- return "";
1056
+ if (typeof s !== "string") return "";
1024
1057
  return s.charAt(0).toUpperCase() + s.slice(1);
1025
1058
  };
1026
1059
  var extractInlineTypes = (item) => {
@@ -1033,7 +1066,7 @@ var extractInlineTypes = (item) => {
1033
1066
  const accumulator = [item];
1034
1067
  for (const node of walk(item)) {
1035
1068
  if (node.kind === "UnionTypeDefinition") {
1036
- node.types = (0, import_lodash.default)(node.types, (type) => type.name.value);
1069
+ node.types = (0, import_es_toolkit.uniqBy)(node.types, (type) => type.name.value);
1037
1070
  }
1038
1071
  if (node.kind === "NamedType") {
1039
1072
  if (typeof node.name.value !== "string") {
@@ -1063,41 +1096,6 @@ function* walk(maybeNode, visited = /* @__PURE__ */ new WeakSet()) {
1063
1096
  yield maybeNode;
1064
1097
  visited.add(maybeNode);
1065
1098
  }
1066
- function addNamespaceToSchema(maybeNode, namespace = []) {
1067
- if (typeof maybeNode === "string") {
1068
- return maybeNode;
1069
- }
1070
- if (typeof maybeNode === "boolean") {
1071
- return maybeNode;
1072
- }
1073
- const newNode = maybeNode;
1074
- const keys = Object.keys(maybeNode);
1075
- Object.values(maybeNode).map((m, index) => {
1076
- const key = keys[index];
1077
- if (Array.isArray(m)) {
1078
- newNode[key] = m.map((element) => {
1079
- if (!element) {
1080
- return;
1081
- }
1082
- if (!element.hasOwnProperty("name")) {
1083
- return element;
1084
- }
1085
- const value = element.name || element.value;
1086
- return addNamespaceToSchema(element, [...namespace, value]);
1087
- });
1088
- } else {
1089
- if (!m) {
1090
- return;
1091
- }
1092
- if (!m.hasOwnProperty("name")) {
1093
- newNode[key] = m;
1094
- } else {
1095
- newNode[key] = addNamespaceToSchema(m, [...namespace, m.name]);
1096
- }
1097
- }
1098
- });
1099
- return { ...newNode, namespace };
1100
- }
1101
1099
  var generateNamespacedFieldName = (names, suffix = "") => {
1102
1100
  return (suffix ? [...names, suffix] : names).map(capitalize).join("");
1103
1101
  };
@@ -1257,6 +1255,11 @@ var scalarDefinitions = [
1257
1255
  required: true,
1258
1256
  type: astBuilder.TYPES.String
1259
1257
  }),
1258
+ astBuilder.FieldDefinition({
1259
+ name: "hasReferences",
1260
+ required: false,
1261
+ type: astBuilder.TYPES.Boolean
1262
+ }),
1260
1263
  astBuilder.FieldDefinition({
1261
1264
  name: "breadcrumbs",
1262
1265
  required: true,
@@ -1433,13 +1436,12 @@ var checkPasswordHash = async ({
1433
1436
  return true;
1434
1437
  };
1435
1438
  var mapUserFields = (collectable, prefix = []) => {
1436
- var _a, _b, _c, _d, _e;
1437
1439
  const results = [];
1438
- const passwordFields = ((_a = collectable.fields) == null ? void 0 : _a.filter((field) => field.type === "password")) || [];
1440
+ const passwordFields = collectable.fields?.filter((field) => field.type === "password") || [];
1439
1441
  if (passwordFields.length > 1) {
1440
1442
  throw new Error("Only one password field is allowed");
1441
1443
  }
1442
- const idFields = ((_b = collectable.fields) == null ? void 0 : _b.filter((field) => field.uid)) || [];
1444
+ const idFields = collectable.fields?.filter((field) => field.uid) || [];
1443
1445
  if (idFields.length > 1) {
1444
1446
  throw new Error("Only one uid field is allowed");
1445
1447
  }
@@ -1447,11 +1449,11 @@ var mapUserFields = (collectable, prefix = []) => {
1447
1449
  results.push({
1448
1450
  path: prefix,
1449
1451
  collectable,
1450
- idFieldName: (_c = idFields[0]) == null ? void 0 : _c.name,
1451
- passwordFieldName: (_d = passwordFields[0]) == null ? void 0 : _d.name
1452
+ idFieldName: idFields[0]?.name,
1453
+ passwordFieldName: passwordFields[0]?.name
1452
1454
  });
1453
1455
  }
1454
- (_e = collectable.fields) == null ? void 0 : _e.forEach((field) => {
1456
+ collectable.fields?.forEach((field) => {
1455
1457
  if (field.type === "object" && field.fields) {
1456
1458
  results.push(...mapUserFields(field, [...prefix, field.name]));
1457
1459
  }
@@ -1471,6 +1473,19 @@ var Builder = class {
1471
1473
  this.addToLookupMap = (lookup) => {
1472
1474
  this.lookupMap[lookup.type] = lookup;
1473
1475
  };
1476
+ /**
1477
+ * ```graphql
1478
+ * # ex.
1479
+ * {
1480
+ * getCollection(collection: $collection) {
1481
+ * name
1482
+ * documents {...}
1483
+ * }
1484
+ * }
1485
+ * ```
1486
+ *
1487
+ * @param collections
1488
+ */
1474
1489
  this.buildCollectionDefinition = async (collections) => {
1475
1490
  const name = "collection";
1476
1491
  const typeName = "Collection";
@@ -1541,6 +1556,19 @@ var Builder = class {
1541
1556
  required: true
1542
1557
  });
1543
1558
  };
1559
+ /**
1560
+ * ```graphql
1561
+ * # ex.
1562
+ * {
1563
+ * getCollections {
1564
+ * name
1565
+ * documents {...}
1566
+ * }
1567
+ * }
1568
+ * ```
1569
+ *
1570
+ * @param collections
1571
+ */
1544
1572
  this.buildMultiCollectionDefinition = async (collections) => {
1545
1573
  const name = "collections";
1546
1574
  const typeName = "Collection";
@@ -1551,6 +1579,17 @@ var Builder = class {
1551
1579
  required: true
1552
1580
  });
1553
1581
  };
1582
+ /**
1583
+ * ```graphql
1584
+ * # ex.
1585
+ * {
1586
+ * node(id: $id) {
1587
+ * id
1588
+ * data {...}
1589
+ * }
1590
+ * }
1591
+ * ```
1592
+ */
1554
1593
  this.multiNodeDocument = async () => {
1555
1594
  const name = "node";
1556
1595
  const args = [
@@ -1571,6 +1610,19 @@ var Builder = class {
1571
1610
  required: true
1572
1611
  });
1573
1612
  };
1613
+ /**
1614
+ * ```graphql
1615
+ * # ex.
1616
+ * {
1617
+ * getDocument(collection: $collection, relativePath: $relativePath) {
1618
+ * id
1619
+ * data {...}
1620
+ * }
1621
+ * }
1622
+ * ```
1623
+ *
1624
+ * @param collections
1625
+ */
1574
1626
  this.multiCollectionDocument = async (collections) => {
1575
1627
  const name = "document";
1576
1628
  const args = [
@@ -1596,6 +1648,19 @@ var Builder = class {
1596
1648
  required: true
1597
1649
  });
1598
1650
  };
1651
+ /**
1652
+ * ```graphql
1653
+ * # ex.
1654
+ * {
1655
+ * addPendingDocument(collection: $collection, relativePath: $relativePath, params: $params) {
1656
+ * id
1657
+ * data {...}
1658
+ * }
1659
+ * }
1660
+ * ```
1661
+ *
1662
+ * @param collections
1663
+ */
1599
1664
  this.addMultiCollectionDocumentMutation = async () => {
1600
1665
  return astBuilder.FieldDefinition({
1601
1666
  name: "addPendingDocument",
@@ -1620,6 +1685,19 @@ var Builder = class {
1620
1685
  type: astBuilder.TYPES.MultiCollectionDocument
1621
1686
  });
1622
1687
  };
1688
+ /**
1689
+ * ```graphql
1690
+ * # ex.
1691
+ * {
1692
+ * createDocument(relativePath: $relativePath, params: $params) {
1693
+ * id
1694
+ * data {...}
1695
+ * }
1696
+ * }
1697
+ * ```
1698
+ *
1699
+ * @param collections
1700
+ */
1623
1701
  this.buildCreateCollectionDocumentMutation = async (collections) => {
1624
1702
  return astBuilder.FieldDefinition({
1625
1703
  name: "createDocument",
@@ -1647,6 +1725,19 @@ var Builder = class {
1647
1725
  type: astBuilder.TYPES.MultiCollectionDocument
1648
1726
  });
1649
1727
  };
1728
+ /**
1729
+ * ```graphql
1730
+ * # ex.
1731
+ * {
1732
+ * updateDocument(relativePath: $relativePath, params: $params) {
1733
+ * id
1734
+ * data {...}
1735
+ * }
1736
+ * }
1737
+ * ```
1738
+ *
1739
+ * @param collections
1740
+ */
1650
1741
  this.buildUpdateCollectionDocumentMutation = async (collections) => {
1651
1742
  return astBuilder.FieldDefinition({
1652
1743
  name: "updateDocument",
@@ -1674,6 +1765,19 @@ var Builder = class {
1674
1765
  type: astBuilder.TYPES.MultiCollectionDocument
1675
1766
  });
1676
1767
  };
1768
+ /**
1769
+ * ```graphql
1770
+ * # ex.
1771
+ * {
1772
+ * deleteDocument(relativePath: $relativePath, params: $params) {
1773
+ * id
1774
+ * data {...}
1775
+ * }
1776
+ * }
1777
+ * ```
1778
+ *
1779
+ * @param collections
1780
+ */
1677
1781
  this.buildDeleteCollectionDocumentMutation = async (collections) => {
1678
1782
  return astBuilder.FieldDefinition({
1679
1783
  name: "deleteDocument",
@@ -1693,6 +1797,19 @@ var Builder = class {
1693
1797
  type: astBuilder.TYPES.MultiCollectionDocument
1694
1798
  });
1695
1799
  };
1800
+ /**
1801
+ * ```graphql
1802
+ * # ex.
1803
+ * {
1804
+ * createFolder(folderName: $folderName, params: $params) {
1805
+ * id
1806
+ * data {...}
1807
+ * }
1808
+ * }
1809
+ * ```
1810
+ *
1811
+ * @param collections
1812
+ */
1696
1813
  this.buildCreateCollectionFolderMutation = async () => {
1697
1814
  return astBuilder.FieldDefinition({
1698
1815
  name: "createFolder",
@@ -1712,6 +1829,19 @@ var Builder = class {
1712
1829
  type: astBuilder.TYPES.MultiCollectionDocument
1713
1830
  });
1714
1831
  };
1832
+ /**
1833
+ * ```graphql
1834
+ * # ex.
1835
+ * {
1836
+ * getPostDocument(relativePath: $relativePath) {
1837
+ * id
1838
+ * data {...}
1839
+ * }
1840
+ * }
1841
+ * ```
1842
+ *
1843
+ * @param collection
1844
+ */
1715
1845
  this.collectionDocument = async (collection) => {
1716
1846
  const name = NAMER.queryName([collection.name]);
1717
1847
  const type = await this._buildCollectionDocumentType(collection);
@@ -1772,6 +1902,20 @@ var Builder = class {
1772
1902
  const args = [];
1773
1903
  return astBuilder.FieldDefinition({ type, name, args, required: false });
1774
1904
  };
1905
+ /**
1906
+ * Turns a collection into a fragment that gets updated on build. This fragment does not resolve references
1907
+ * ```graphql
1908
+ * # ex.
1909
+ * fragment AuthorsParts on Authors {
1910
+ * name
1911
+ * avatar
1912
+ * ...
1913
+ * }
1914
+ * ```
1915
+ *
1916
+ * @public
1917
+ * @param collection a TinaCloud collection
1918
+ */
1775
1919
  this.collectionFragment = async (collection) => {
1776
1920
  const name = NAMER.dataTypeName(collection.namespace);
1777
1921
  const fragmentName = NAMER.fragmentName(collection.namespace);
@@ -1785,14 +1929,27 @@ var Builder = class {
1785
1929
  selections: filterSelections(selections)
1786
1930
  });
1787
1931
  };
1932
+ /**
1933
+ * Given a collection this function returns its selections set. For example for Post this would return
1934
+ *
1935
+ * "
1936
+ * body
1937
+ * title
1938
+ * ... on Author {
1939
+ * name
1940
+ * heroImg
1941
+ * }
1942
+ *
1943
+ * But in the AST format
1944
+ *
1945
+ * */
1788
1946
  this._getCollectionFragmentSelections = async (collection, depth) => {
1789
- var _a;
1790
1947
  const selections = [];
1791
1948
  selections.push({
1792
1949
  name: { kind: "Name", value: "__typename" },
1793
1950
  kind: "Field"
1794
1951
  });
1795
- if (((_a = collection.fields) == null ? void 0 : _a.length) > 0) {
1952
+ if (collection.fields?.length > 0) {
1796
1953
  await sequential(collection.fields, async (x) => {
1797
1954
  const field = await this._buildFieldNodeForFragments(x, depth);
1798
1955
  selections.push(field);
@@ -1807,7 +1964,6 @@ var Builder = class {
1807
1964
  return selections;
1808
1965
  };
1809
1966
  this._buildFieldNodeForFragments = async (field, depth) => {
1810
- var _a, _b;
1811
1967
  switch (field.type) {
1812
1968
  case "string":
1813
1969
  case "image":
@@ -1840,7 +1996,7 @@ var Builder = class {
1840
1996
  selections: filterSelections([passwordValue, passwordChangeRequired])
1841
1997
  });
1842
1998
  case "object":
1843
- if (((_a = field.fields) == null ? void 0 : _a.length) > 0) {
1999
+ if (field.fields?.length > 0) {
1844
2000
  const selections2 = [];
1845
2001
  await sequential(field.fields, async (item) => {
1846
2002
  const field2 = await this._buildFieldNodeForFragments(item, depth);
@@ -1853,7 +2009,7 @@ var Builder = class {
1853
2009
  ...filterSelections(selections2)
1854
2010
  ]
1855
2011
  });
1856
- } else if (((_b = field.templates) == null ? void 0 : _b.length) > 0) {
2012
+ } else if (field.templates?.length > 0) {
1857
2013
  const selections2 = [];
1858
2014
  await sequential(field.templates, async (tem) => {
1859
2015
  if (typeof tem === "object") {
@@ -1868,9 +2024,9 @@ var Builder = class {
1868
2024
  ]
1869
2025
  });
1870
2026
  }
2027
+ // TODO: Should we throw here?
1871
2028
  case "reference":
1872
- if (depth >= this.maxDepth)
1873
- return false;
2029
+ if (depth >= this.maxDepth) return false;
1874
2030
  if (!("collections" in field)) {
1875
2031
  return false;
1876
2032
  }
@@ -1902,6 +2058,7 @@ var Builder = class {
1902
2058
  name: field.name,
1903
2059
  selections: [
1904
2060
  ...selections,
2061
+ // This is ... on Document { id }
1905
2062
  {
1906
2063
  kind: "InlineFragment",
1907
2064
  typeCondition: {
@@ -1932,6 +2089,19 @@ var Builder = class {
1932
2089
  });
1933
2090
  }
1934
2091
  };
2092
+ /**
2093
+ * ```graphql
2094
+ * # ex.
2095
+ * mutation {
2096
+ * updatePostDocument(relativePath: $relativePath, params: $params) {
2097
+ * id
2098
+ * data {...}
2099
+ * }
2100
+ * }
2101
+ * ```
2102
+ *
2103
+ * @param collection
2104
+ */
1935
2105
  this.updateCollectionDocumentMutation = async (collection) => {
1936
2106
  return astBuilder.FieldDefinition({
1937
2107
  type: await this._buildCollectionDocumentType(collection),
@@ -1951,6 +2121,19 @@ var Builder = class {
1951
2121
  ]
1952
2122
  });
1953
2123
  };
2124
+ /**
2125
+ * ```graphql
2126
+ * # ex.
2127
+ * mutation {
2128
+ * createPostDocument(relativePath: $relativePath, params: $params) {
2129
+ * id
2130
+ * data {...}
2131
+ * }
2132
+ * }
2133
+ * ```
2134
+ *
2135
+ * @param collection
2136
+ */
1954
2137
  this.createCollectionDocumentMutation = async (collection) => {
1955
2138
  return astBuilder.FieldDefinition({
1956
2139
  type: await this._buildCollectionDocumentType(collection),
@@ -1970,6 +2153,22 @@ var Builder = class {
1970
2153
  ]
1971
2154
  });
1972
2155
  };
2156
+ /**
2157
+ * ```graphql
2158
+ * # ex.
2159
+ * {
2160
+ * getPostList(first: 10) {
2161
+ * edges {
2162
+ * node {
2163
+ * id
2164
+ * }
2165
+ * }
2166
+ * }
2167
+ * }
2168
+ * ```
2169
+ *
2170
+ * @param collection
2171
+ */
1973
2172
  this.collectionDocumentList = async (collection) => {
1974
2173
  const connectionName = NAMER.referenceConnectionType(collection.namespace);
1975
2174
  this.addToLookupMap({
@@ -1985,6 +2184,10 @@ var Builder = class {
1985
2184
  collection
1986
2185
  });
1987
2186
  };
2187
+ /**
2188
+ * GraphQL type definitions which remain unchanged regardless
2189
+ * of the supplied Tina schema. Ex. "node" interface
2190
+ */
1988
2191
  this.buildStaticDefinitions = () => staticDefinitions;
1989
2192
  this._buildCollectionDocumentType = async (collection, suffix = "", extraFields = [], extraInterfaces = []) => {
1990
2193
  const documentTypeName = NAMER.documentTypeName(collection.namespace);
@@ -2468,7 +2671,7 @@ var Builder = class {
2468
2671
  this.addToLookupMap({
2469
2672
  type: name,
2470
2673
  resolveType: "unionData",
2471
- collection: collection == null ? void 0 : collection.name,
2674
+ collection: collection?.name,
2472
2675
  typeMap
2473
2676
  });
2474
2677
  return astBuilder.UnionTypeDefinition({ name, types });
@@ -2489,6 +2692,7 @@ var Builder = class {
2489
2692
  name: NAMER.dataFilterTypeName(namespace),
2490
2693
  fields: await sequential(collections, async (collection2) => {
2491
2694
  return astBuilder.InputValueDefinition({
2695
+ // @ts-ignore
2492
2696
  name: collection2.name,
2493
2697
  type: NAMER.dataFilterTypeName(collection2.namespace)
2494
2698
  });
@@ -2574,7 +2778,7 @@ var Builder = class {
2574
2778
  this._buildDataField = async (field) => {
2575
2779
  const listWarningMsg = `
2576
2780
  WARNING: The user interface for ${field.type} does not support \`list: true\`
2577
- Visit https://tina.io/docs/errors/ui-not-supported/ for more information
2781
+ Visit https://tina.io/docs/r/content-fields/#list-fields/ for more information
2578
2782
 
2579
2783
  `;
2580
2784
  switch (field.type) {
@@ -2677,8 +2881,8 @@ Visit https://tina.io/docs/errors/ui-not-supported/ for more information
2677
2881
  ]
2678
2882
  });
2679
2883
  };
2680
- var _a, _b, _c, _d;
2681
- this.maxDepth = (_d = (_c = (_b = (_a = config == null ? void 0 : config.tinaSchema.schema) == null ? void 0 : _a.config) == null ? void 0 : _b.client) == null ? void 0 : _c.referenceDepth) != null ? _d : 2;
2884
+ this.maxDepth = // @ts-ignore
2885
+ config?.tinaSchema.schema?.config?.client?.referenceDepth ?? 2;
2682
2886
  this.tinaSchema = config.tinaSchema;
2683
2887
  this.lookupMap = {};
2684
2888
  }
@@ -2689,8 +2893,7 @@ Visit https://tina.io/docs/errors/ui-not-supported/ for more information
2689
2893
  selections.push(field);
2690
2894
  });
2691
2895
  const filteredSelections = filterSelections(selections);
2692
- if (!filteredSelections.length)
2693
- return false;
2896
+ if (!filteredSelections.length) return false;
2694
2897
  return astBuilder.InlineFragmentDefinition({
2695
2898
  selections: filteredSelections,
2696
2899
  name: NAMER.dataTypeName(template.namespace)
@@ -2724,12 +2927,13 @@ var filterSelections = (arr) => {
2724
2927
  };
2725
2928
 
2726
2929
  // src/schema/createSchema.ts
2727
- var import_schema_tools2 = require("@tinacms/schema-tools");
2930
+ var import_schema_tools3 = require("@tinacms/schema-tools");
2728
2931
 
2729
2932
  // src/schema/validate.ts
2730
- var import_lodash2 = __toESM(require("lodash.clonedeep"));
2731
- var yup2 = __toESM(require("yup"));
2732
2933
  var import_schema_tools = require("@tinacms/schema-tools");
2934
+ var yup2 = __toESM(require("yup"));
2935
+ var import_es_toolkit2 = require("es-toolkit");
2936
+ var import_schema_tools2 = require("@tinacms/schema-tools");
2733
2937
  var FIELD_TYPES = [
2734
2938
  "string",
2735
2939
  "number",
@@ -2742,8 +2946,8 @@ var FIELD_TYPES = [
2742
2946
  "password"
2743
2947
  ];
2744
2948
  var validateSchema = async (schema) => {
2745
- const schema2 = addNamespaceToSchema(
2746
- (0, import_lodash2.default)(schema)
2949
+ const schema2 = (0, import_schema_tools.addNamespaceToSchema)(
2950
+ (0, import_es_toolkit2.cloneDeep)(schema)
2747
2951
  );
2748
2952
  const collections = await sequential(
2749
2953
  schema2.collections,
@@ -2751,7 +2955,7 @@ var validateSchema = async (schema) => {
2751
2955
  );
2752
2956
  validationCollectionsPathAndMatch(collections);
2753
2957
  if (schema2.config) {
2754
- const config = (0, import_schema_tools.validateTinaCloudSchemaConfig)(schema2.config);
2958
+ const config = (0, import_schema_tools2.validateTinaCloudSchemaConfig)(schema2.config);
2755
2959
  return {
2756
2960
  collections,
2757
2961
  config
@@ -2767,20 +2971,18 @@ var validationCollectionsPathAndMatch = (collections) => {
2767
2971
  return;
2768
2972
  }
2769
2973
  const noMatchCollections = collections.filter((x) => {
2770
- return typeof (x == null ? void 0 : x.match) === "undefined";
2974
+ return typeof x?.match === "undefined";
2771
2975
  }).map((x) => `${x.path}${x.format || "md"}`);
2772
2976
  if (noMatchCollections.length !== new Set(noMatchCollections).size) {
2773
2977
  throw new Error(
2978
+ // TODO: add a link to the docs
2774
2979
  "Two collections without match can not have the same `path`. Please make the `path` unique or add a matches property to the collection."
2775
2980
  );
2776
2981
  }
2777
2982
  const hasMatchAndPath = collections.filter((x) => {
2778
2983
  return typeof x.path !== "undefined" && typeof x.match !== "undefined";
2779
2984
  }).map(
2780
- (x) => {
2781
- var _a, _b;
2782
- return `${x.path}|${((_a = x == null ? void 0 : x.match) == null ? void 0 : _a.exclude) || ""}|${((_b = x == null ? void 0 : x.match) == null ? void 0 : _b.include) || ""}|${x.format || "md"}`;
2783
- }
2985
+ (x) => `${x.path}|${x?.match?.exclude || ""}|${x?.match?.include || ""}|${x.format || "md"}`
2784
2986
  );
2785
2987
  if (hasMatchAndPath.length !== new Set(hasMatchAndPath).size) {
2786
2988
  throw new Error(
@@ -2804,7 +3006,7 @@ var validationCollectionsPathAndMatch = (collections) => {
2804
3006
  );
2805
3007
  }
2806
3008
  const matches = collectionsArr.map(
2807
- (x) => typeof (x == null ? void 0 : x.match) === "object" ? JSON.stringify(x.match) : ""
3009
+ (x) => typeof x?.match === "object" ? JSON.stringify(x.match) : ""
2808
3010
  );
2809
3011
  if (matches.length === new Set(matches).size) {
2810
3012
  return;
@@ -2882,7 +3084,7 @@ var validateField = async (field) => {
2882
3084
  // package.json
2883
3085
  var package_default = {
2884
3086
  name: "@tinacms/graphql",
2885
- version: "1.5.6",
3087
+ version: "1.6.1",
2886
3088
  main: "dist/index.js",
2887
3089
  module: "dist/index.mjs",
2888
3090
  typings: "dist/index.d.ts",
@@ -2908,33 +3110,30 @@ var package_default = {
2908
3110
  types: "pnpm tsc",
2909
3111
  build: "tinacms-scripts build",
2910
3112
  docs: "pnpm typedoc",
2911
- serve: "pnpm nodemon dist/server.js",
2912
- test: "jest",
2913
- "test-watch": "jest --watch"
3113
+ test: "vitest run",
3114
+ "test-watch": "vitest"
2914
3115
  },
2915
3116
  dependencies: {
2916
- "@iarna/toml": "^2.2.5",
3117
+ "@iarna/toml": "catalog:",
2917
3118
  "@tinacms/mdx": "workspace:*",
2918
3119
  "@tinacms/schema-tools": "workspace:*",
2919
- "abstract-level": "^1.0.4",
3120
+ "abstract-level": "catalog:",
2920
3121
  "date-fns": "^2.30.0",
2921
- "fast-glob": "^3.3.2",
2922
- "fs-extra": "^11.2.0",
2923
- "glob-parent": "^6.0.2",
3122
+ "es-toolkit": "^1.42.0",
3123
+ "fast-glob": "catalog:",
3124
+ "fs-extra": "catalog:",
3125
+ "glob-parent": "catalog:",
2924
3126
  graphql: "15.8.0",
2925
- "gray-matter": "^4.0.3",
2926
- "isomorphic-git": "^1.27.1",
2927
- "js-sha1": "^0.6.0",
3127
+ "gray-matter": "catalog:",
3128
+ "isomorphic-git": "catalog:",
3129
+ "js-sha1": "catalog:",
2928
3130
  "js-yaml": "^3.14.1",
2929
- "jsonpath-plus": "^6.0.1",
2930
- "lodash.clonedeep": "^4.5.0",
2931
- "lodash.set": "^4.3.2",
2932
- "lodash.uniqby": "^4.7.0",
2933
- "many-level": "^2.0.0",
2934
- micromatch: "4.0.8",
2935
- "normalize-path": "^3.0.0",
2936
- "readable-stream": "^4.5.2",
2937
- scmp: "^2.1.0",
3131
+ "jsonpath-plus": "catalog:",
3132
+ "many-level": "catalog:",
3133
+ micromatch: "catalog:",
3134
+ "normalize-path": "catalog:",
3135
+ "readable-stream": "catalog:",
3136
+ scmp: "catalog:",
2938
3137
  yup: "^0.32.11"
2939
3138
  },
2940
3139
  publishConfig: {
@@ -2949,26 +3148,22 @@ var package_default = {
2949
3148
  "@tinacms/scripts": "workspace:*",
2950
3149
  "@types/cors": "^2.8.17",
2951
3150
  "@types/estree": "^0.0.50",
2952
- "@types/express": "^4.17.21",
3151
+ "@types/express": "catalog:",
2953
3152
  "@types/fs-extra": "^9.0.13",
2954
- "@types/jest": "^26.0.24",
2955
3153
  "@types/js-yaml": "^3.12.10",
2956
- "@types/lodash.camelcase": "^4.3.9",
2957
- "@types/lodash.upperfirst": "^4.3.9",
2958
- "@types/lru-cache": "^5.1.1",
2959
- "@types/mdast": "^3.0.15",
2960
- "@types/micromatch": "^4.0.9",
2961
- "@types/node": "^22.7.4",
2962
- "@types/normalize-path": "^3.0.2",
2963
- "@types/ws": "^7.4.7",
3154
+ "@types/lru-cache": "catalog:",
3155
+ "@types/mdast": "catalog:",
3156
+ "@types/micromatch": "catalog:",
3157
+ "@types/node": "^22.13.1",
3158
+ "@types/normalize-path": "catalog:",
3159
+ "@types/ws": "catalog:",
2964
3160
  "@types/yup": "^0.29.14",
2965
- jest: "^29.7.0",
2966
- "jest-diff": "^29.7.0",
2967
3161
  "jest-file-snapshot": "^0.5.0",
2968
- "jest-matcher-utils": "^29.7.0",
2969
- "memory-level": "^1.0.0",
2970
- nodemon: "3.1.4",
2971
- typescript: "^5.6.2"
3162
+ "memory-level": "catalog:",
3163
+ typescript: "^5.7.3",
3164
+ vite: "^4.5.9",
3165
+ vitest: "^0.32.4",
3166
+ zod: "catalog:"
2972
3167
  }
2973
3168
  };
2974
3169
 
@@ -2983,7 +3178,7 @@ var createSchema = async ({
2983
3178
  if (flags && flags.length > 0) {
2984
3179
  meta["flags"] = flags;
2985
3180
  }
2986
- return new import_schema_tools2.TinaSchema({
3181
+ return new import_schema_tools3.TinaSchema({
2987
3182
  version: {
2988
3183
  fullVersion: package_default.version,
2989
3184
  major,
@@ -3038,8 +3233,9 @@ var _buildFragments = async (builder, tinaSchema) => {
3038
3233
  });
3039
3234
  const fragDoc = {
3040
3235
  kind: "Document",
3041
- definitions: (0, import_lodash3.default)(
3236
+ definitions: (0, import_es_toolkit3.uniqBy)(
3042
3237
  extractInlineTypes(fragmentDefinitionsFields),
3238
+ // @ts-ignore - all nodes returned by extractInlineTypes have a name property
3043
3239
  (node) => node.name.value
3044
3240
  )
3045
3241
  };
@@ -3049,7 +3245,6 @@ var _buildQueries = async (builder, tinaSchema) => {
3049
3245
  const operationsDefinitions = [];
3050
3246
  const collections = tinaSchema.getCollections();
3051
3247
  await sequential(collections, async (collection) => {
3052
- var _a, _b, _c;
3053
3248
  const queryName = NAMER.queryName(collection.namespace);
3054
3249
  const queryListName = NAMER.generateQueryListName(collection.namespace);
3055
3250
  const queryFilterTypeName = NAMER.dataFilterTypeName(collection.namespace);
@@ -3062,16 +3257,18 @@ var _buildQueries = async (builder, tinaSchema) => {
3062
3257
  fragName,
3063
3258
  queryName: queryListName,
3064
3259
  filterType: queryFilterTypeName,
3260
+ // look for flag to see if the data layer is enabled
3065
3261
  dataLayer: Boolean(
3066
- (_c = (_b = (_a = tinaSchema.config) == null ? void 0 : _a.meta) == null ? void 0 : _b.flags) == null ? void 0 : _c.find((x) => x === "experimentalData")
3262
+ tinaSchema.config?.meta?.flags?.find((x) => x === "experimentalData")
3067
3263
  )
3068
3264
  })
3069
3265
  );
3070
3266
  });
3071
3267
  const queryDoc = {
3072
3268
  kind: "Document",
3073
- definitions: (0, import_lodash3.default)(
3269
+ definitions: (0, import_es_toolkit3.uniqBy)(
3074
3270
  extractInlineTypes(operationsDefinitions),
3271
+ // @ts-ignore - all nodes returned by extractInlineTypes have a name property
3075
3272
  (node) => node.name.value
3076
3273
  )
3077
3274
  };
@@ -3122,7 +3319,9 @@ var _buildSchema = async (builder, tinaSchema) => {
3122
3319
  await builder.buildCreateCollectionFolderMutation()
3123
3320
  );
3124
3321
  await sequential(collections, async (collection) => {
3125
- queryTypeDefinitionFields.push(await builder.collectionDocument(collection));
3322
+ queryTypeDefinitionFields.push(
3323
+ await builder.collectionDocument(collection)
3324
+ );
3126
3325
  if (collection.isAuthCollection) {
3127
3326
  queryTypeDefinitionFields.push(
3128
3327
  await builder.authenticationCollectionDocument(collection)
@@ -3156,13 +3355,15 @@ var _buildSchema = async (builder, tinaSchema) => {
3156
3355
  fields: mutationTypeDefinitionFields
3157
3356
  })
3158
3357
  );
3159
- return {
3358
+ const schema = {
3160
3359
  kind: "Document",
3161
- definitions: (0, import_lodash3.default)(
3360
+ definitions: (0, import_es_toolkit3.uniqBy)(
3162
3361
  extractInlineTypes(definitions),
3362
+ // @ts-ignore - all nodes returned by extractInlineTypes have a name property
3163
3363
  (node) => node.name.value
3164
3364
  )
3165
3365
  };
3366
+ return schema;
3166
3367
  };
3167
3368
 
3168
3369
  // src/resolve.ts
@@ -3171,395 +3372,156 @@ var import_graphql5 = require("graphql");
3171
3372
  // src/resolver/index.ts
3172
3373
  var import_path3 = __toESM(require("path"));
3173
3374
  var import_isValid = __toESM(require("date-fns/isValid/index.js"));
3375
+ var import_jsonpath_plus2 = require("jsonpath-plus");
3174
3376
 
3175
3377
  // src/mdx/index.ts
3176
3378
  var import_mdx = require("@tinacms/mdx");
3177
3379
 
3178
- // src/resolver/error.ts
3179
- var TinaGraphQLError = class extends Error {
3180
- constructor(message, extensions) {
3181
- super(message);
3182
- if (!this.name) {
3183
- Object.defineProperty(this, "name", { value: "TinaGraphQLError" });
3184
- }
3185
- this.extensions = { ...extensions };
3186
- }
3380
+ // src/resolver/index.ts
3381
+ var import_graphql3 = require("graphql");
3382
+
3383
+ // src/database/datalayer.ts
3384
+ var import_jsonpath_plus = require("jsonpath-plus");
3385
+ var import_js_sha1 = __toESM(require("js-sha1"));
3386
+
3387
+ // src/database/level.ts
3388
+ var ARRAY_ITEM_VALUE_SEPARATOR = ",";
3389
+ var INDEX_KEY_FIELD_SEPARATOR = "";
3390
+ var CONTENT_ROOT_PREFIX = "~";
3391
+ var SUBLEVEL_OPTIONS = {
3392
+ separator: INDEX_KEY_FIELD_SEPARATOR,
3393
+ valueEncoding: "json"
3187
3394
  };
3188
- var TinaFetchError = class extends Error {
3189
- constructor(message, args) {
3190
- super(message);
3191
- this.name = "TinaFetchError";
3192
- this.collection = args.collection;
3193
- this.stack = args.stack;
3194
- this.file = args.file;
3195
- this.originalError = args.originalError;
3395
+ var LevelProxyHandler = {
3396
+ get: function(target, property) {
3397
+ if (!target[property]) {
3398
+ throw new Error(`The property, ${property.toString()}, doesn't exist`);
3399
+ }
3400
+ if (typeof target[property] !== "function") {
3401
+ throw new Error(
3402
+ `The property, ${property.toString()}, is not a function`
3403
+ );
3404
+ }
3405
+ if (property === "get") {
3406
+ return async (...args) => {
3407
+ let result;
3408
+ try {
3409
+ result = await target[property].apply(target, args);
3410
+ } catch (e) {
3411
+ if (e.code !== "LEVEL_NOT_FOUND") {
3412
+ throw e;
3413
+ }
3414
+ }
3415
+ return result;
3416
+ };
3417
+ } else if (property === "sublevel") {
3418
+ return (...args) => {
3419
+ return new Proxy(
3420
+ // eslint-disable-next-line prefer-spread
3421
+ target[property].apply(target, args),
3422
+ LevelProxyHandler
3423
+ );
3424
+ };
3425
+ } else {
3426
+ return (...args) => target[property].apply(target, args);
3427
+ }
3196
3428
  }
3197
3429
  };
3198
- var TinaQueryError = class extends TinaFetchError {
3199
- constructor(args) {
3200
- super(
3201
- `Error querying file ${args.file} from collection ${args.collection}. ${auditMessage(args.includeAuditMessage)}`,
3202
- args
3203
- );
3430
+ var LevelProxy = class {
3431
+ constructor(level) {
3432
+ return new Proxy(level, LevelProxyHandler);
3204
3433
  }
3205
3434
  };
3206
- var TinaParseDocumentError = class extends TinaFetchError {
3207
- constructor(args) {
3208
- super(
3209
- `Error parsing file ${args.file} from collection ${args.collection}. ${auditMessage(args.includeAuditMessage)}`,
3210
- args
3435
+
3436
+ // src/database/datalayer.ts
3437
+ var import_path2 = __toESM(require("path"));
3438
+
3439
+ // src/database/util.ts
3440
+ var import_toml = __toESM(require("@iarna/toml"));
3441
+ var import_schema_tools4 = require("@tinacms/schema-tools");
3442
+ var import_gray_matter = __toESM(require("gray-matter"));
3443
+ var import_js_yaml = __toESM(require("js-yaml"));
3444
+ var import_path = __toESM(require("path"));
3445
+ var import_micromatch = __toESM(require("micromatch"));
3446
+
3447
+ // src/database/alias-utils.ts
3448
+ var replaceBlockAliases = (template, item) => {
3449
+ const output = { ...item };
3450
+ const templateKey = template.templateKey || "_template";
3451
+ const templateName = output[templateKey];
3452
+ const matchingTemplate = template.templates.find(
3453
+ (t) => t.nameOverride == templateName || t.name == templateName
3454
+ );
3455
+ if (!matchingTemplate) {
3456
+ throw new Error(
3457
+ `Block template "${templateName}" is not defined for field "${template.name}"`
3211
3458
  );
3212
3459
  }
3213
- toString() {
3214
- return super.toString() + "\n OriginalError: \n" + this.originalError.toString();
3460
+ output._template = matchingTemplate.name;
3461
+ if (templateKey != "_template") {
3462
+ delete output[templateKey];
3215
3463
  }
3464
+ return output;
3216
3465
  };
3217
- var auditMessage = (includeAuditMessage = true) => includeAuditMessage ? `Please run "tinacms audit" or add the --verbose option for more info` : "";
3218
- var handleFetchErrorError = (e, verbose) => {
3219
- if (e instanceof Error) {
3220
- if (e instanceof TinaFetchError) {
3221
- if (verbose) {
3222
- console.log(e.toString());
3223
- console.log(e);
3224
- console.log(e.stack);
3466
+ var replaceNameOverrides = (template, obj) => {
3467
+ if (template.list) {
3468
+ return obj.map((item) => {
3469
+ if (isBlockField(template)) {
3470
+ item = replaceBlockAliases(template, item);
3225
3471
  }
3226
- }
3472
+ return _replaceNameOverrides(
3473
+ getTemplateForData(template, item).fields,
3474
+ item
3475
+ );
3476
+ });
3227
3477
  } else {
3228
- console.error(e);
3478
+ return _replaceNameOverrides(getTemplateForData(template, obj).fields, obj);
3229
3479
  }
3230
- throw e;
3231
3480
  };
3232
-
3233
- // src/resolver/filter-utils.ts
3234
- var resolveReferences = async (filter, fields, resolver) => {
3235
- for (const fieldKey of Object.keys(filter)) {
3236
- const fieldDefinition = fields.find(
3237
- (f) => f.name === fieldKey
3481
+ function isBlockField(field) {
3482
+ return field && field.type === "object" && field.templates?.length > 0;
3483
+ }
3484
+ var _replaceNameOverrides = (fields, obj) => {
3485
+ const output = {};
3486
+ Object.keys(obj).forEach((key) => {
3487
+ const field = fields.find(
3488
+ (fieldWithMatchingAlias) => (fieldWithMatchingAlias?.nameOverride || fieldWithMatchingAlias?.name) === key
3238
3489
  );
3239
- if (fieldDefinition) {
3240
- if (fieldDefinition.type === "reference") {
3241
- const { edges, values } = await resolver(filter, fieldDefinition);
3242
- if (edges.length === 1) {
3243
- filter[fieldKey] = {
3244
- eq: values[0]
3245
- };
3246
- } else if (edges.length > 1) {
3247
- filter[fieldKey] = {
3248
- in: values
3249
- };
3250
- } else {
3251
- filter[fieldKey] = {
3252
- eq: "___null___"
3253
- };
3254
- }
3255
- } else if (fieldDefinition.type === "object") {
3256
- if (fieldDefinition.templates) {
3257
- for (const templateName of Object.keys(filter[fieldKey])) {
3258
- const template = fieldDefinition.templates.find(
3259
- (template2) => !(typeof template2 === "string") && template2.name === templateName
3260
- );
3261
- if (template) {
3262
- await resolveReferences(
3263
- filter[fieldKey][templateName],
3264
- template.fields,
3265
- resolver
3266
- );
3267
- } else {
3268
- throw new Error(`Template ${templateName} not found`);
3269
- }
3270
- }
3271
- } else {
3272
- await resolveReferences(
3273
- filter[fieldKey],
3274
- fieldDefinition.fields,
3275
- resolver
3276
- );
3277
- }
3490
+ output[field?.name || key] = field?.type == "object" ? replaceNameOverrides(field, obj[key]) : obj[key];
3491
+ });
3492
+ return output;
3493
+ };
3494
+ var getTemplateForData = (field, data) => {
3495
+ if (field.templates?.length) {
3496
+ const templateKey = "_template";
3497
+ if (data[templateKey]) {
3498
+ const result = field.templates.find(
3499
+ (template) => template.nameOverride === data[templateKey] || template.name === data[templateKey]
3500
+ );
3501
+ if (result) {
3502
+ return result;
3278
3503
  }
3279
- } else {
3280
- throw new Error(`Unable to find field ${fieldKey}`);
3504
+ throw new Error(
3505
+ `Template "${data[templateKey]}" is not defined for field "${field.name}"`
3506
+ );
3281
3507
  }
3508
+ throw new Error(
3509
+ `Missing required key "${templateKey}" on field "${field.name}"`
3510
+ );
3511
+ } else {
3512
+ return field;
3282
3513
  }
3283
3514
  };
3284
- var collectConditionsForChildFields = (filterNode, fields, pathExpression, collectCondition) => {
3285
- for (const childFieldName of Object.keys(filterNode)) {
3286
- const childField = fields.find((field) => field.name === childFieldName);
3287
- if (!childField) {
3288
- throw new Error(`Unable to find type for field ${childFieldName}`);
3289
- }
3290
- collectConditionsForField(
3291
- childFieldName,
3292
- childField,
3293
- filterNode[childFieldName],
3294
- pathExpression,
3295
- collectCondition
3296
- );
3297
- }
3298
- };
3299
- var collectConditionsForObjectField = (fieldName, field, filterNode, pathExpression, collectCondition) => {
3300
- if (field.list && field.templates) {
3301
- for (const [filterKey, childFilterNode] of Object.entries(filterNode)) {
3302
- const template = field.templates.find(
3303
- (template2) => !(typeof template2 === "string") && template2.name === filterKey
3304
- );
3305
- const jsonPath = `${fieldName}[?(@._template=="${filterKey}")]`;
3306
- const filterPath = pathExpression ? `${pathExpression}.${jsonPath}` : jsonPath;
3307
- collectConditionsForChildFields(
3308
- childFilterNode,
3309
- template.fields,
3310
- filterPath,
3311
- collectCondition
3312
- );
3313
- }
3314
- } else {
3315
- const jsonPath = `${fieldName}${field.list ? "[*]" : ""}`;
3316
- const filterPath = pathExpression ? `${pathExpression}.${jsonPath}` : `${jsonPath}`;
3317
- collectConditionsForChildFields(
3318
- filterNode,
3319
- field.fields,
3320
- filterPath,
3321
- collectCondition
3322
- );
3323
- }
3324
- };
3325
- var collectConditionsForField = (fieldName, field, filterNode, pathExpression, collectCondition) => {
3326
- if (field.type === "object") {
3327
- collectConditionsForObjectField(
3328
- fieldName,
3329
- field,
3330
- filterNode,
3331
- pathExpression,
3332
- collectCondition
3333
- );
3334
- } else {
3335
- collectCondition({
3336
- filterPath: pathExpression ? `${pathExpression}.${fieldName}` : fieldName,
3337
- filterExpression: {
3338
- _type: field.type,
3339
- _list: !!field.list,
3340
- ...filterNode
3341
- }
3342
- });
3343
- }
3344
- };
3345
-
3346
- // src/resolver/media-utils.ts
3347
- var resolveMediaCloudToRelative = (value, config = { useRelativeMedia: true }, schema) => {
3348
- if (config && value) {
3349
- if (config.useRelativeMedia === true) {
3350
- return value;
3351
- }
3352
- if (hasTinaMediaConfig(schema) === true) {
3353
- const assetsURL = `https://${config.assetsHost}/${config.clientId}`;
3354
- if (typeof value === "string" && value.includes(assetsURL)) {
3355
- const cleanMediaRoot = cleanUpSlashes(
3356
- schema.config.media.tina.mediaRoot
3357
- );
3358
- const strippedURL = value.replace(assetsURL, "");
3359
- return `${cleanMediaRoot}${strippedURL}`;
3360
- }
3361
- if (Array.isArray(value)) {
3362
- return value.map((v) => {
3363
- if (!v || typeof v !== "string")
3364
- return v;
3365
- const cleanMediaRoot = cleanUpSlashes(
3366
- schema.config.media.tina.mediaRoot
3367
- );
3368
- const strippedURL = v.replace(assetsURL, "");
3369
- return `${cleanMediaRoot}${strippedURL}`;
3370
- });
3371
- }
3372
- return value;
3373
- }
3374
- return value;
3375
- } else {
3376
- return value;
3377
- }
3378
- };
3379
- var resolveMediaRelativeToCloud = (value, config = { useRelativeMedia: true }, schema) => {
3380
- if (config && value) {
3381
- if (config.useRelativeMedia === true) {
3382
- return value;
3383
- }
3384
- if (hasTinaMediaConfig(schema) === true) {
3385
- const cleanMediaRoot = cleanUpSlashes(schema.config.media.tina.mediaRoot);
3386
- if (typeof value === "string") {
3387
- const strippedValue = value.replace(cleanMediaRoot, "");
3388
- return `https://${config.assetsHost}/${config.clientId}${strippedValue}`;
3389
- }
3390
- if (Array.isArray(value)) {
3391
- return value.map((v) => {
3392
- if (!v || typeof v !== "string")
3393
- return v;
3394
- const strippedValue = v.replace(cleanMediaRoot, "");
3395
- return `https://${config.assetsHost}/${config.clientId}${strippedValue}`;
3396
- });
3397
- }
3398
- }
3399
- return value;
3400
- } else {
3401
- return value;
3402
- }
3403
- };
3404
- var cleanUpSlashes = (path7) => {
3405
- if (path7) {
3406
- return `/${path7.replace(/^\/+|\/+$/gm, "")}`;
3407
- }
3408
- return "";
3409
- };
3410
- var hasTinaMediaConfig = (schema) => {
3411
- var _a, _b, _c, _d, _e, _f, _g, _h;
3412
- if (!((_b = (_a = schema.config) == null ? void 0 : _a.media) == null ? void 0 : _b.tina))
3413
- return false;
3414
- if (typeof ((_e = (_d = (_c = schema.config) == null ? void 0 : _c.media) == null ? void 0 : _d.tina) == null ? void 0 : _e.publicFolder) !== "string" && typeof ((_h = (_g = (_f = schema.config) == null ? void 0 : _f.media) == null ? void 0 : _g.tina) == null ? void 0 : _h.mediaRoot) !== "string")
3415
- return false;
3416
- return true;
3417
- };
3418
-
3419
- // src/resolver/index.ts
3420
- var import_graphql3 = require("graphql");
3421
-
3422
- // src/database/datalayer.ts
3423
- var import_jsonpath_plus = require("jsonpath-plus");
3424
- var import_js_sha1 = __toESM(require("js-sha1"));
3425
-
3426
- // src/database/level.ts
3427
- var ARRAY_ITEM_VALUE_SEPARATOR = ",";
3428
- var INDEX_KEY_FIELD_SEPARATOR = "";
3429
- var CONTENT_ROOT_PREFIX = "~";
3430
- var SUBLEVEL_OPTIONS = {
3431
- separator: INDEX_KEY_FIELD_SEPARATOR,
3432
- valueEncoding: "json"
3433
- };
3434
- var LevelProxyHandler = {
3435
- get: function(target, property) {
3436
- if (!target[property]) {
3437
- throw new Error(`The property, ${property.toString()}, doesn't exist`);
3438
- }
3439
- if (typeof target[property] !== "function") {
3440
- throw new Error(`The property, ${property.toString()}, is not a function`);
3441
- }
3442
- if (property === "get") {
3443
- return async (...args) => {
3444
- let result;
3445
- try {
3446
- result = await target[property].apply(target, args);
3447
- } catch (e) {
3448
- if (e.code !== "LEVEL_NOT_FOUND") {
3449
- throw e;
3450
- }
3451
- }
3452
- return result;
3453
- };
3454
- } else if (property === "sublevel") {
3455
- return (...args) => {
3456
- return new Proxy(
3457
- target[property].apply(target, args),
3458
- LevelProxyHandler
3459
- );
3460
- };
3461
- } else {
3462
- return (...args) => target[property].apply(target, args);
3463
- }
3464
- }
3465
- };
3466
- var LevelProxy = class {
3467
- constructor(level) {
3468
- return new Proxy(level, LevelProxyHandler);
3469
- }
3470
- };
3471
-
3472
- // src/database/datalayer.ts
3473
- var import_path2 = __toESM(require("path"));
3474
-
3475
- // src/database/util.ts
3476
- var import_toml = __toESM(require("@iarna/toml"));
3477
- var import_js_yaml = __toESM(require("js-yaml"));
3478
- var import_gray_matter = __toESM(require("gray-matter"));
3479
- var import_schema_tools3 = require("@tinacms/schema-tools");
3480
- var import_micromatch = __toESM(require("micromatch"));
3481
- var import_path = __toESM(require("path"));
3482
-
3483
- // src/database/alias-utils.ts
3484
- var replaceBlockAliases = (template, item) => {
3485
- const output = { ...item };
3486
- const templateKey = template.templateKey || "_template";
3487
- const templateName = output[templateKey];
3488
- const matchingTemplate = template.templates.find(
3489
- (t) => t.nameOverride == templateName || t.name == templateName
3490
- );
3491
- if (!matchingTemplate) {
3492
- throw new Error(
3493
- `Block template "${templateName}" is not defined for field "${template.name}"`
3494
- );
3495
- }
3496
- output._template = matchingTemplate.name;
3497
- if (templateKey != "_template") {
3498
- delete output[templateKey];
3499
- }
3500
- return output;
3501
- };
3502
- var replaceNameOverrides = (template, obj) => {
3503
- if (template.list) {
3504
- return obj.map((item) => {
3505
- if (isBlockField(template)) {
3506
- item = replaceBlockAliases(template, item);
3507
- }
3508
- return _replaceNameOverrides(
3509
- getTemplateForData(template, item).fields,
3510
- item
3511
- );
3512
- });
3513
- } else {
3514
- return _replaceNameOverrides(getTemplateForData(template, obj).fields, obj);
3515
- }
3516
- };
3517
- function isBlockField(field) {
3518
- var _a;
3519
- return field && field.type === "object" && ((_a = field.templates) == null ? void 0 : _a.length) > 0;
3520
- }
3521
- var _replaceNameOverrides = (fields, obj) => {
3522
- const output = {};
3523
- Object.keys(obj).forEach((key) => {
3524
- const field = fields.find(
3525
- (fieldWithMatchingAlias) => ((fieldWithMatchingAlias == null ? void 0 : fieldWithMatchingAlias.nameOverride) || (fieldWithMatchingAlias == null ? void 0 : fieldWithMatchingAlias.name)) === key
3526
- );
3527
- output[(field == null ? void 0 : field.name) || key] = (field == null ? void 0 : field.type) == "object" ? replaceNameOverrides(field, obj[key]) : obj[key];
3528
- });
3529
- return output;
3530
- };
3531
- var getTemplateForData = (field, data) => {
3532
- var _a;
3533
- if ((_a = field.templates) == null ? void 0 : _a.length) {
3534
- const templateKey = "_template";
3535
- if (data[templateKey]) {
3536
- const result = field.templates.find(
3537
- (template) => template.nameOverride === data[templateKey] || template.name === data[templateKey]
3538
- );
3539
- if (result) {
3540
- return result;
3541
- }
3542
- throw new Error(
3543
- `Template "${data[templateKey]}" is not defined for field "${field.name}"`
3544
- );
3545
- }
3546
- throw new Error(
3547
- `Missing required key "${templateKey}" on field "${field.name}"`
3548
- );
3549
- } else {
3550
- return field;
3551
- }
3552
- };
3553
- var applyBlockAliases = (template, item) => {
3554
- const output = { ...item };
3555
- const templateKey = template.templateKey || "_template";
3556
- const templateName = output._template;
3557
- const matchingTemplate = template.templates.find(
3558
- (t) => t.nameOverride == templateName || t.name == templateName
3559
- );
3560
- if (!matchingTemplate) {
3561
- throw new Error(
3562
- `Block template "${templateName}" is not defined for field "${template.name}"`
3515
+ var applyBlockAliases = (template, item) => {
3516
+ const output = { ...item };
3517
+ const templateKey = template.templateKey || "_template";
3518
+ const templateName = output._template;
3519
+ const matchingTemplate = template.templates.find(
3520
+ (t) => t.nameOverride == templateName || t.name == templateName
3521
+ );
3522
+ if (!matchingTemplate) {
3523
+ throw new Error(
3524
+ `Block template "${templateName}" is not defined for field "${template.name}"`
3563
3525
  );
3564
3526
  }
3565
3527
  output[templateKey] = matchingTemplate.nameOverride || matchingTemplate.name;
@@ -3588,8 +3550,8 @@ var _applyNameOverrides = (fields, obj) => {
3588
3550
  const output = {};
3589
3551
  Object.keys(obj).forEach((key) => {
3590
3552
  const field = fields.find((field2) => field2.name === key);
3591
- const outputKey = (field == null ? void 0 : field.nameOverride) || key;
3592
- output[outputKey] = (field == null ? void 0 : field.type) === "object" ? applyNameOverrides(field, obj[key]) : obj[key];
3553
+ const outputKey = field?.nameOverride || key;
3554
+ output[outputKey] = field?.type === "object" ? applyNameOverrides(field, obj[key]) : obj[key];
3593
3555
  });
3594
3556
  return output;
3595
3557
  };
@@ -3602,7 +3564,6 @@ var matterEngines = {
3602
3564
  }
3603
3565
  };
3604
3566
  var stringifyFile = (content, format, keepTemplateKey, markdownParseConfig) => {
3605
- var _a, _b;
3606
3567
  const {
3607
3568
  _relativePath,
3608
3569
  _keepTemplateKey,
@@ -3626,9 +3587,9 @@ var stringifyFile = (content, format, keepTemplateKey, markdownParseConfig) => {
3626
3587
  ${$_body}`,
3627
3588
  strippedContent,
3628
3589
  {
3629
- language: (_a = markdownParseConfig == null ? void 0 : markdownParseConfig.frontmatterFormat) != null ? _a : "yaml",
3590
+ language: markdownParseConfig?.frontmatterFormat ?? "yaml",
3630
3591
  engines: matterEngines,
3631
- delimiters: (_b = markdownParseConfig == null ? void 0 : markdownParseConfig.frontmatterDelimiters) != null ? _b : "---"
3592
+ delimiters: markdownParseConfig?.frontmatterDelimiters ?? "---"
3632
3593
  }
3633
3594
  );
3634
3595
  return ok;
@@ -3644,15 +3605,14 @@ ${$_body}`,
3644
3605
  }
3645
3606
  };
3646
3607
  var parseFile = (content, format, yupSchema, markdownParseConfig) => {
3647
- var _a, _b;
3648
3608
  try {
3649
3609
  switch (format) {
3650
3610
  case ".markdown":
3651
3611
  case ".mdx":
3652
3612
  case ".md":
3653
3613
  const contentJSON = (0, import_gray_matter.default)(content || "", {
3654
- language: (_a = markdownParseConfig == null ? void 0 : markdownParseConfig.frontmatterFormat) != null ? _a : "yaml",
3655
- delimiters: (_b = markdownParseConfig == null ? void 0 : markdownParseConfig.frontmatterDelimiters) != null ? _b : "---",
3614
+ language: markdownParseConfig?.frontmatterFormat ?? "yaml",
3615
+ delimiters: markdownParseConfig?.frontmatterDelimiters ?? "---",
3656
3616
  engines: matterEngines
3657
3617
  });
3658
3618
  const markdownData = {
@@ -3689,7 +3649,7 @@ var scanAllContent = async (tinaSchema, bridge, callback) => {
3689
3649
  const filesSeen = /* @__PURE__ */ new Map();
3690
3650
  const duplicateFiles = /* @__PURE__ */ new Set();
3691
3651
  await sequential(tinaSchema.getCollections(), async (collection) => {
3692
- const normalPath = (0, import_schema_tools3.normalizePath)(collection.path);
3652
+ const normalPath = (0, import_schema_tools4.normalizePath)(collection.path);
3693
3653
  const format = collection.format || "md";
3694
3654
  const documentPaths = await bridge.glob(normalPath, format);
3695
3655
  const matches = tinaSchema.getMatches({ collection });
@@ -3751,7 +3711,7 @@ var transformDocument = (filepath, contentObject, tinaSchema) => {
3751
3711
  ),
3752
3712
  template: void 0
3753
3713
  } : tinaSchema.getCollectionAndTemplateByFullPath(filepath, templateName);
3754
- const field = template == null ? void 0 : template.fields.find((field2) => {
3714
+ const field = template?.fields.find((field2) => {
3755
3715
  if (field2.type === "string" || field2.type === "rich-text") {
3756
3716
  if (field2.isBody) {
3757
3717
  return true;
@@ -3771,7 +3731,7 @@ var transformDocument = (filepath, contentObject, tinaSchema) => {
3771
3731
  ...data,
3772
3732
  _collection: collection.name,
3773
3733
  _keepTemplateKey: !!collection.templates,
3774
- _template: (template == null ? void 0 : template.namespace) ? lastItem(template == null ? void 0 : template.namespace) : void 0,
3734
+ _template: template?.namespace ? lastItem(template?.namespace) : void 0,
3775
3735
  _relativePath: filepath.replace(collection.path, "").replace(/^\/|\/$/g, ""),
3776
3736
  _id: filepath
3777
3737
  };
@@ -3780,10 +3740,10 @@ function hasOwnProperty(obj, prop) {
3780
3740
  return obj.hasOwnProperty(prop);
3781
3741
  }
3782
3742
  var getTemplateForFile = (templateInfo, data) => {
3783
- if ((templateInfo == null ? void 0 : templateInfo.type) === "object") {
3743
+ if (templateInfo?.type === "object") {
3784
3744
  return templateInfo.template;
3785
3745
  }
3786
- if ((templateInfo == null ? void 0 : templateInfo.type) === "union") {
3746
+ if (templateInfo?.type === "union") {
3787
3747
  if (hasOwnProperty(data, "_template")) {
3788
3748
  const template = templateInfo.templates.find(
3789
3749
  (t) => lastItem(t.namespace) === data._template
@@ -3801,14 +3761,14 @@ var getTemplateForFile = (templateInfo, data) => {
3801
3761
  throw new Error(`Unable to determine template`);
3802
3762
  };
3803
3763
  var loadAndParseWithAliases = async (bridge, filepath, collection, templateInfo) => {
3804
- const dataString = await bridge.get((0, import_schema_tools3.normalizePath)(filepath));
3764
+ const dataString = await bridge.get((0, import_schema_tools4.normalizePath)(filepath));
3805
3765
  const data = parseFile(
3806
3766
  dataString,
3807
3767
  import_path.default.extname(filepath),
3808
3768
  (yup3) => yup3.object({}),
3809
3769
  {
3810
- frontmatterDelimiters: collection == null ? void 0 : collection.frontmatterDelimiters,
3811
- frontmatterFormat: collection == null ? void 0 : collection.frontmatterFormat
3770
+ frontmatterDelimiters: collection?.frontmatterDelimiters,
3771
+ frontmatterFormat: collection?.frontmatterFormat
3812
3772
  }
3813
3773
  );
3814
3774
  const template = getTemplateForFile(templateInfo, data);
@@ -3823,6 +3783,9 @@ var loadAndParseWithAliases = async (bridge, filepath, collection, templateInfo)
3823
3783
 
3824
3784
  // src/database/datalayer.ts
3825
3785
  var DEFAULT_COLLECTION_SORT_KEY = "__filepath__";
3786
+ var REFS_COLLECTIONS_SORT_KEY = "__refs__";
3787
+ var REFS_REFERENCE_FIELD = "__tina_ref__";
3788
+ var REFS_PATH_FIELD = "__tina_ref_path__";
3826
3789
  var DEFAULT_NUMERIC_LPAD = 4;
3827
3790
  var applyPadding = (input, pad) => {
3828
3791
  if (pad) {
@@ -4280,7 +4243,7 @@ var FolderTreeBuilder = class {
4280
4243
  return this._tree;
4281
4244
  }
4282
4245
  update(documentPath, collectionPath) {
4283
- let folderPath = import_path2.default.dirname((0, import_schema_tools3.normalizePath)(documentPath));
4246
+ let folderPath = import_path2.default.dirname((0, import_schema_tools4.normalizePath)(documentPath));
4284
4247
  if (folderPath === ".") {
4285
4248
  folderPath = "";
4286
4249
  }
@@ -4293,7 +4256,7 @@ var FolderTreeBuilder = class {
4293
4256
  if (!this._tree[current2]) {
4294
4257
  this._tree[current2] = /* @__PURE__ */ new Set();
4295
4258
  }
4296
- this._tree[current2].add((0, import_schema_tools3.normalizePath)(import_path2.default.join(current2, part)));
4259
+ this._tree[current2].add((0, import_schema_tools4.normalizePath)(import_path2.default.join(current2, part)));
4297
4260
  parent.push(part);
4298
4261
  });
4299
4262
  const current = parent.join("/");
@@ -4332,6 +4295,7 @@ var makeFolderOpsForCollection = (folderTree, collection, indexDefinitions, opTy
4332
4295
  result.push({
4333
4296
  type: opType,
4334
4297
  key: `${collection.path}/${subFolderKey}.${collection.format}`,
4298
+ // replace the root with the collection path
4335
4299
  sublevel: indexSublevel,
4336
4300
  value: {}
4337
4301
  });
@@ -4395,6 +4359,57 @@ var makeIndexOpsForDocument = (filepath, collection, indexDefinitions, data, opT
4395
4359
  }
4396
4360
  return result;
4397
4361
  };
4362
+ var makeRefOpsForDocument = (filepath, collection, references, data, opType, level) => {
4363
+ const result = [];
4364
+ if (collection) {
4365
+ for (const [c, referencePaths] of Object.entries(references || {})) {
4366
+ if (!referencePaths.length) {
4367
+ continue;
4368
+ }
4369
+ const collectionSublevel = level.sublevel(c, SUBLEVEL_OPTIONS);
4370
+ const refSublevel = collectionSublevel.sublevel(
4371
+ REFS_COLLECTIONS_SORT_KEY,
4372
+ SUBLEVEL_OPTIONS
4373
+ );
4374
+ const references2 = {};
4375
+ for (const path7 of referencePaths) {
4376
+ const ref = (0, import_jsonpath_plus.JSONPath)({ path: path7, json: data });
4377
+ if (!ref) {
4378
+ continue;
4379
+ }
4380
+ if (Array.isArray(ref)) {
4381
+ for (const r of ref) {
4382
+ if (!r) {
4383
+ continue;
4384
+ }
4385
+ if (references2[r]) {
4386
+ references2[r].push(path7);
4387
+ } else {
4388
+ references2[r] = [path7];
4389
+ }
4390
+ }
4391
+ } else {
4392
+ if (references2[ref]) {
4393
+ references2[ref].push(path7);
4394
+ } else {
4395
+ references2[ref] = [path7];
4396
+ }
4397
+ }
4398
+ }
4399
+ for (const ref of Object.keys(references2)) {
4400
+ for (const path7 of references2[ref]) {
4401
+ result.push({
4402
+ type: opType,
4403
+ key: `${ref}${INDEX_KEY_FIELD_SEPARATOR}${path7}${INDEX_KEY_FIELD_SEPARATOR}${filepath}`,
4404
+ sublevel: refSublevel,
4405
+ value: opType === "put" ? {} : void 0
4406
+ });
4407
+ }
4408
+ }
4409
+ }
4410
+ }
4411
+ return result;
4412
+ };
4398
4413
  var makeStringEscaper = (regex, replacement) => {
4399
4414
  return (input) => {
4400
4415
  if (Array.isArray(input)) {
@@ -4408,19 +4423,254 @@ var makeStringEscaper = (regex, replacement) => {
4408
4423
  return input;
4409
4424
  }
4410
4425
  }
4411
- };
4426
+ };
4427
+ };
4428
+ var stringEscaper = makeStringEscaper(
4429
+ new RegExp(INDEX_KEY_FIELD_SEPARATOR, "gm"),
4430
+ encodeURIComponent(INDEX_KEY_FIELD_SEPARATOR)
4431
+ );
4432
+
4433
+ // src/resolver/error.ts
4434
+ var TinaGraphQLError = class extends Error {
4435
+ constructor(message, extensions) {
4436
+ super(message);
4437
+ if (!this.name) {
4438
+ Object.defineProperty(this, "name", { value: "TinaGraphQLError" });
4439
+ }
4440
+ this.extensions = { ...extensions };
4441
+ }
4442
+ };
4443
+ var TinaFetchError = class extends Error {
4444
+ constructor(message, args) {
4445
+ super(message);
4446
+ this.name = "TinaFetchError";
4447
+ this.collection = args.collection;
4448
+ this.file = args.file;
4449
+ this.originalError = args.originalError;
4450
+ }
4451
+ };
4452
+ var TinaQueryError = class extends TinaFetchError {
4453
+ constructor(args) {
4454
+ super(
4455
+ `Error querying file ${args.file} from collection ${args.collection}. ${auditMessage(args.includeAuditMessage)}`,
4456
+ args
4457
+ );
4458
+ }
4459
+ };
4460
+ var TinaParseDocumentError = class extends TinaFetchError {
4461
+ constructor(args) {
4462
+ super(
4463
+ `Error parsing file ${args.file} from collection ${args.collection}. ${auditMessage(args.includeAuditMessage)}`,
4464
+ args
4465
+ );
4466
+ }
4467
+ toString() {
4468
+ return super.toString() + "\n OriginalError: \n" + this.originalError.toString();
4469
+ }
4470
+ };
4471
+ var auditMessage = (includeAuditMessage = true) => includeAuditMessage ? `Please run "tinacms audit" or add the --verbose option for more info` : "";
4472
+ var handleFetchErrorError = (e, verbose) => {
4473
+ if (e instanceof Error) {
4474
+ if (e instanceof TinaFetchError) {
4475
+ if (verbose) {
4476
+ console.log(e.toString());
4477
+ console.log(e);
4478
+ console.log(e.stack);
4479
+ }
4480
+ }
4481
+ } else {
4482
+ console.error(e);
4483
+ }
4484
+ throw e;
4485
+ };
4486
+
4487
+ // src/resolver/filter-utils.ts
4488
+ var resolveReferences = async (filter, fields, resolver) => {
4489
+ for (const fieldKey of Object.keys(filter)) {
4490
+ const fieldDefinition = fields.find(
4491
+ (f) => f.name === fieldKey
4492
+ );
4493
+ if (fieldDefinition) {
4494
+ if (fieldDefinition.type === "reference") {
4495
+ const { edges, values } = await resolver(filter, fieldDefinition);
4496
+ if (edges.length === 1) {
4497
+ filter[fieldKey] = {
4498
+ eq: values[0]
4499
+ };
4500
+ } else if (edges.length > 1) {
4501
+ filter[fieldKey] = {
4502
+ in: values
4503
+ };
4504
+ } else {
4505
+ filter[fieldKey] = {
4506
+ eq: "___null___"
4507
+ };
4508
+ }
4509
+ } else if (fieldDefinition.type === "object") {
4510
+ if (fieldDefinition.templates) {
4511
+ for (const templateName of Object.keys(filter[fieldKey])) {
4512
+ const template = fieldDefinition.templates.find(
4513
+ (template2) => !(typeof template2 === "string") && template2.name === templateName
4514
+ );
4515
+ if (template) {
4516
+ await resolveReferences(
4517
+ filter[fieldKey][templateName],
4518
+ template.fields,
4519
+ resolver
4520
+ );
4521
+ } else {
4522
+ throw new Error(`Template ${templateName} not found`);
4523
+ }
4524
+ }
4525
+ } else {
4526
+ await resolveReferences(
4527
+ filter[fieldKey],
4528
+ fieldDefinition.fields,
4529
+ resolver
4530
+ );
4531
+ }
4532
+ }
4533
+ } else {
4534
+ throw new Error(`Unable to find field ${fieldKey}`);
4535
+ }
4536
+ }
4537
+ };
4538
+ var collectConditionsForChildFields = (filterNode, fields, pathExpression, collectCondition) => {
4539
+ for (const childFieldName of Object.keys(filterNode)) {
4540
+ const childField = fields.find((field) => field.name === childFieldName);
4541
+ if (!childField) {
4542
+ throw new Error(`Unable to find type for field ${childFieldName}`);
4543
+ }
4544
+ collectConditionsForField(
4545
+ childFieldName,
4546
+ childField,
4547
+ filterNode[childFieldName],
4548
+ pathExpression,
4549
+ collectCondition
4550
+ );
4551
+ }
4552
+ };
4553
+ var collectConditionsForObjectField = (fieldName, field, filterNode, pathExpression, collectCondition) => {
4554
+ if (field.list && field.templates) {
4555
+ for (const [filterKey, childFilterNode] of Object.entries(filterNode)) {
4556
+ const template = field.templates.find(
4557
+ (template2) => !(typeof template2 === "string") && template2.name === filterKey
4558
+ );
4559
+ const jsonPath = `${fieldName}[?(@._template=="${filterKey}")]`;
4560
+ const filterPath = pathExpression ? `${pathExpression}.${jsonPath}` : jsonPath;
4561
+ collectConditionsForChildFields(
4562
+ childFilterNode,
4563
+ template.fields,
4564
+ filterPath,
4565
+ collectCondition
4566
+ );
4567
+ }
4568
+ } else {
4569
+ const jsonPath = `${fieldName}${field.list ? "[*]" : ""}`;
4570
+ const filterPath = pathExpression ? `${pathExpression}.${jsonPath}` : `${jsonPath}`;
4571
+ collectConditionsForChildFields(
4572
+ filterNode,
4573
+ field.fields,
4574
+ filterPath,
4575
+ collectCondition
4576
+ );
4577
+ }
4578
+ };
4579
+ var collectConditionsForField = (fieldName, field, filterNode, pathExpression, collectCondition) => {
4580
+ if (field.type === "object") {
4581
+ collectConditionsForObjectField(
4582
+ fieldName,
4583
+ field,
4584
+ filterNode,
4585
+ pathExpression,
4586
+ collectCondition
4587
+ );
4588
+ } else {
4589
+ collectCondition({
4590
+ filterPath: pathExpression ? `${pathExpression}.${fieldName}` : fieldName,
4591
+ filterExpression: {
4592
+ _type: field.type,
4593
+ _list: !!field.list,
4594
+ ...filterNode
4595
+ }
4596
+ });
4597
+ }
4598
+ };
4599
+
4600
+ // src/resolver/media-utils.ts
4601
+ var resolveMediaCloudToRelative = (value, config = { useRelativeMedia: true }, schema) => {
4602
+ if (config && value) {
4603
+ if (config.useRelativeMedia === true) {
4604
+ return value;
4605
+ }
4606
+ if (hasTinaMediaConfig(schema) === true) {
4607
+ const assetsURL = `https://${config.assetsHost}/${config.clientId}`;
4608
+ if (typeof value === "string" && value.includes(assetsURL)) {
4609
+ const cleanMediaRoot = cleanUpSlashes(
4610
+ schema.config.media.tina.mediaRoot
4611
+ );
4612
+ const strippedURL = value.replace(assetsURL, "");
4613
+ return `${cleanMediaRoot}${strippedURL}`;
4614
+ }
4615
+ if (Array.isArray(value)) {
4616
+ return value.map((v) => {
4617
+ if (!v || typeof v !== "string") return v;
4618
+ const cleanMediaRoot = cleanUpSlashes(
4619
+ schema.config.media.tina.mediaRoot
4620
+ );
4621
+ const strippedURL = v.replace(assetsURL, "");
4622
+ return `${cleanMediaRoot}${strippedURL}`;
4623
+ });
4624
+ }
4625
+ return value;
4626
+ }
4627
+ return value;
4628
+ } else {
4629
+ return value;
4630
+ }
4631
+ };
4632
+ var resolveMediaRelativeToCloud = (value, config = { useRelativeMedia: true }, schema) => {
4633
+ if (config && value) {
4634
+ if (config.useRelativeMedia === true) {
4635
+ return value;
4636
+ }
4637
+ if (hasTinaMediaConfig(schema) === true) {
4638
+ const cleanMediaRoot = cleanUpSlashes(schema.config.media.tina.mediaRoot);
4639
+ if (typeof value === "string") {
4640
+ const strippedValue = value.replace(cleanMediaRoot, "");
4641
+ return `https://${config.assetsHost}/${config.clientId}${strippedValue}`;
4642
+ }
4643
+ if (Array.isArray(value)) {
4644
+ return value.map((v) => {
4645
+ if (!v || typeof v !== "string") return v;
4646
+ const strippedValue = v.replace(cleanMediaRoot, "");
4647
+ return `https://${config.assetsHost}/${config.clientId}${strippedValue}`;
4648
+ });
4649
+ }
4650
+ }
4651
+ return value;
4652
+ } else {
4653
+ return value;
4654
+ }
4655
+ };
4656
+ var cleanUpSlashes = (path7) => {
4657
+ if (path7) {
4658
+ return `/${path7.replace(/^\/+|\/+$/gm, "")}`;
4659
+ }
4660
+ return "";
4661
+ };
4662
+ var hasTinaMediaConfig = (schema) => {
4663
+ if (!schema.config?.media?.tina) return false;
4664
+ if (typeof schema.config?.media?.tina?.publicFolder !== "string" && typeof schema.config?.media?.tina?.mediaRoot !== "string")
4665
+ return false;
4666
+ return true;
4412
4667
  };
4413
- var stringEscaper = makeStringEscaper(
4414
- new RegExp(INDEX_KEY_FIELD_SEPARATOR, "gm"),
4415
- encodeURIComponent(INDEX_KEY_FIELD_SEPARATOR)
4416
- );
4417
4668
 
4418
4669
  // src/resolver/index.ts
4419
4670
  var createResolver = (args) => {
4420
4671
  return new Resolver(args);
4421
4672
  };
4422
4673
  var resolveFieldData = async ({ namespace, ...field }, rawData, accumulator, tinaSchema, config, isAudit) => {
4423
- var _a, _b;
4424
4674
  if (!rawData) {
4425
4675
  return void 0;
4426
4676
  }
@@ -4447,7 +4697,8 @@ var resolveFieldData = async ({ namespace, ...field }, rawData, accumulator, tin
4447
4697
  case "password":
4448
4698
  accumulator[field.name] = {
4449
4699
  value: void 0,
4450
- passwordChangeRequired: (_a = value["passwordChangeRequired"]) != null ? _a : false
4700
+ // never resolve the password hash
4701
+ passwordChangeRequired: value["passwordChangeRequired"] ?? false
4451
4702
  };
4452
4703
  break;
4453
4704
  case "image":
@@ -4463,11 +4714,11 @@ var resolveFieldData = async ({ namespace, ...field }, rawData, accumulator, tin
4463
4714
  field,
4464
4715
  (value2) => resolveMediaRelativeToCloud(value2, config, tinaSchema.schema)
4465
4716
  );
4466
- if (((_b = tree == null ? void 0 : tree.children[0]) == null ? void 0 : _b.type) === "invalid_markdown") {
4717
+ if (tree?.children[0]?.type === "invalid_markdown") {
4467
4718
  if (isAudit) {
4468
- const invalidNode = tree == null ? void 0 : tree.children[0];
4719
+ const invalidNode = tree?.children[0];
4469
4720
  throw new import_graphql3.GraphQLError(
4470
- `${invalidNode == null ? void 0 : invalidNode.message}${invalidNode.position ? ` at line ${invalidNode.position.start.line}, column ${invalidNode.position.start.column}` : ""}`
4721
+ `${invalidNode?.message}${invalidNode.position ? ` at line ${invalidNode.position.start.line}, column ${invalidNode.position.start.column}` : ""}`
4471
4722
  );
4472
4723
  }
4473
4724
  }
@@ -4541,7 +4792,7 @@ var resolveFieldData = async ({ namespace, ...field }, rawData, accumulator, tin
4541
4792
  }
4542
4793
  return accumulator;
4543
4794
  };
4544
- var transformDocumentIntoPayload = async (fullPath, rawData, tinaSchema, config, isAudit) => {
4795
+ var transformDocumentIntoPayload = async (fullPath, rawData, tinaSchema, config, isAudit, hasReferences) => {
4545
4796
  const collection = tinaSchema.getCollection(rawData._collection);
4546
4797
  try {
4547
4798
  const template = tinaSchema.getTemplateForData({
@@ -4575,16 +4826,15 @@ var transformDocumentIntoPayload = async (fullPath, rawData, tinaSchema, config,
4575
4826
  originalError: e,
4576
4827
  collection: collection.name,
4577
4828
  includeAuditMessage: !isAudit,
4578
- file: relativePath,
4579
- stack: e.stack
4829
+ file: relativePath
4580
4830
  });
4581
4831
  }
4582
4832
  const titleField = template.fields.find((x) => {
4583
- if (x.type === "string" && (x == null ? void 0 : x.isTitle)) {
4833
+ if (x.type === "string" && x?.isTitle) {
4584
4834
  return true;
4585
4835
  }
4586
4836
  });
4587
- const titleFieldName = titleField == null ? void 0 : titleField.name;
4837
+ const titleFieldName = titleField?.name;
4588
4838
  const title = data[titleFieldName || " "] || null;
4589
4839
  return {
4590
4840
  __typename: collection.fields ? NAMER.documentTypeName(collection.namespace) : NAMER.documentTypeName(template.namespace),
@@ -4595,6 +4845,7 @@ var transformDocumentIntoPayload = async (fullPath, rawData, tinaSchema, config,
4595
4845
  basename,
4596
4846
  filename,
4597
4847
  extension,
4848
+ hasReferences,
4598
4849
  path: fullPath,
4599
4850
  relativePath,
4600
4851
  breadcrumbs,
@@ -4614,6 +4865,34 @@ var transformDocumentIntoPayload = async (fullPath, rawData, tinaSchema, config,
4614
4865
  throw e;
4615
4866
  }
4616
4867
  };
4868
+ var updateObjectWithJsonPath = (obj, path7, oldValue, newValue) => {
4869
+ let updated = false;
4870
+ if (!path7.includes(".") && !path7.includes("[")) {
4871
+ if (path7 in obj && obj[path7] === oldValue) {
4872
+ obj[path7] = newValue;
4873
+ updated = true;
4874
+ }
4875
+ return { object: obj, updated };
4876
+ }
4877
+ const parentPath = path7.replace(/\.[^.\[\]]+$/, "");
4878
+ const keyToUpdate = path7.match(/[^.\[\]]+$/)[0];
4879
+ const parents = (0, import_jsonpath_plus2.JSONPath)({
4880
+ path: parentPath,
4881
+ json: obj,
4882
+ resultType: "value"
4883
+ });
4884
+ if (parents.length > 0) {
4885
+ parents.forEach((parent) => {
4886
+ if (parent && typeof parent === "object" && keyToUpdate in parent) {
4887
+ if (parent[keyToUpdate] === oldValue) {
4888
+ parent[keyToUpdate] = newValue;
4889
+ updated = true;
4890
+ }
4891
+ }
4892
+ });
4893
+ }
4894
+ return { object: obj, updated };
4895
+ };
4617
4896
  var Resolver = class {
4618
4897
  constructor(init) {
4619
4898
  this.init = init;
@@ -4621,6 +4900,7 @@ var Resolver = class {
4621
4900
  const collection = this.tinaSchema.getCollection(collectionName);
4622
4901
  const extraFields = {};
4623
4902
  return {
4903
+ // return the collection and hasDocuments to resolve documents at a lower level
4624
4904
  documents: { collection, hasDocuments },
4625
4905
  ...collection,
4626
4906
  ...extraFields
@@ -4628,7 +4908,9 @@ var Resolver = class {
4628
4908
  };
4629
4909
  this.getRaw = async (fullPath) => {
4630
4910
  if (typeof fullPath !== "string") {
4631
- throw new Error(`fullPath must be of type string for getDocument request`);
4911
+ throw new Error(
4912
+ `fullPath must be of type string for getDocument request`
4913
+ );
4632
4914
  }
4633
4915
  return this.database.get(fullPath);
4634
4916
  };
@@ -4655,22 +4937,28 @@ var Resolver = class {
4655
4937
  );
4656
4938
  }
4657
4939
  };
4658
- this.getDocument = async (fullPath) => {
4940
+ this.getDocument = async (fullPath, opts = {}) => {
4659
4941
  if (typeof fullPath !== "string") {
4660
- throw new Error(`fullPath must be of type string for getDocument request`);
4942
+ throw new Error(
4943
+ `fullPath must be of type string for getDocument request`
4944
+ );
4661
4945
  }
4662
4946
  const rawData = await this.getRaw(fullPath);
4947
+ const hasReferences = opts?.checkReferences ? await this.hasReferences(fullPath, opts.collection) : void 0;
4663
4948
  return transformDocumentIntoPayload(
4664
4949
  fullPath,
4665
4950
  rawData,
4666
4951
  this.tinaSchema,
4667
4952
  this.config,
4668
- this.isAudit
4953
+ this.isAudit,
4954
+ hasReferences
4669
4955
  );
4670
4956
  };
4671
4957
  this.deleteDocument = async (fullPath) => {
4672
4958
  if (typeof fullPath !== "string") {
4673
- throw new Error(`fullPath must be of type string for getDocument request`);
4959
+ throw new Error(
4960
+ `fullPath must be of type string for getDocument request`
4961
+ );
4674
4962
  }
4675
4963
  await this.database.delete(fullPath);
4676
4964
  };
@@ -4696,16 +4984,18 @@ var Resolver = class {
4696
4984
  return this.buildFieldMutations(
4697
4985
  item,
4698
4986
  objectTemplate,
4699
- idField && existingData && (existingData == null ? void 0 : existingData.find(
4987
+ idField && existingData && existingData?.find(
4700
4988
  (d) => d[idField.name] === item[idField.name]
4701
- ))
4989
+ )
4702
4990
  );
4703
4991
  }
4704
4992
  )
4705
4993
  );
4706
4994
  } else {
4707
4995
  return this.buildFieldMutations(
4996
+ // @ts-ignore FIXME Argument of type 'string | object' is not assignable to parameter of type '{ [fieldName: string]: string | object | (string | object)[]; }'
4708
4997
  fieldValue,
4998
+ //@ts-ignore
4709
4999
  objectTemplate,
4710
5000
  existingData
4711
5001
  );
@@ -4717,6 +5007,7 @@ var Resolver = class {
4717
5007
  fieldValue.map(async (item) => {
4718
5008
  if (typeof item === "string") {
4719
5009
  throw new Error(
5010
+ //@ts-ignore
4720
5011
  `Expected object for template value for field ${field.name}`
4721
5012
  );
4722
5013
  }
@@ -4725,16 +5016,19 @@ var Resolver = class {
4725
5016
  });
4726
5017
  const [templateName] = Object.entries(item)[0];
4727
5018
  const template = templates.find(
5019
+ //@ts-ignore
4728
5020
  (template2) => template2.name === templateName
4729
5021
  );
4730
5022
  if (!template) {
4731
5023
  throw new Error(`Expected to find template ${templateName}`);
4732
5024
  }
4733
5025
  return {
5026
+ // @ts-ignore FIXME Argument of type 'unknown' is not assignable to parameter of type '{ [fieldName: string]: string | { [key: string]: unknown; } | (string | { [key: string]: unknown; })[]; }'
4734
5027
  ...await this.buildFieldMutations(
4735
5028
  item[template.name],
4736
5029
  template
4737
5030
  ),
5031
+ //@ts-ignore
4738
5032
  _template: template.name
4739
5033
  };
4740
5034
  })
@@ -4742,6 +5036,7 @@ var Resolver = class {
4742
5036
  } else {
4743
5037
  if (typeof fieldValue === "string") {
4744
5038
  throw new Error(
5039
+ //@ts-ignore
4745
5040
  `Expected object for template value for field ${field.name}`
4746
5041
  );
4747
5042
  }
@@ -4750,16 +5045,19 @@ var Resolver = class {
4750
5045
  });
4751
5046
  const [templateName] = Object.entries(fieldValue)[0];
4752
5047
  const template = templates.find(
5048
+ //@ts-ignore
4753
5049
  (template2) => template2.name === templateName
4754
5050
  );
4755
5051
  if (!template) {
4756
5052
  throw new Error(`Expected to find template ${templateName}`);
4757
5053
  }
4758
5054
  return {
5055
+ // @ts-ignore FIXME Argument of type 'unknown' is not assignable to parameter of type '{ [fieldName: string]: string | { [key: string]: unknown; } | (string | { [key: string]: unknown; })[]; }'
4759
5056
  ...await this.buildFieldMutations(
4760
5057
  fieldValue[template.name],
4761
5058
  template
4762
5059
  ),
5060
+ //@ts-ignore
4763
5061
  _template: template.name
4764
5062
  };
4765
5063
  }
@@ -4799,6 +5097,7 @@ var Resolver = class {
4799
5097
  return this.getDocument(realPath);
4800
5098
  }
4801
5099
  const params = await this.buildObjectMutations(
5100
+ // @ts-ignore
4802
5101
  args.params[collection.name],
4803
5102
  collection
4804
5103
  );
@@ -4813,7 +5112,7 @@ var Resolver = class {
4813
5112
  isCollectionSpecific
4814
5113
  }) => {
4815
5114
  const doc = await this.getDocument(realPath);
4816
- const oldDoc = this.resolveLegacyValues((doc == null ? void 0 : doc._rawData) || {}, collection);
5115
+ const oldDoc = this.resolveLegacyValues(doc?._rawData || {}, collection);
4817
5116
  if (isAddPendingDocument === true) {
4818
5117
  const templateInfo = this.tinaSchema.getTemplatesForCollectable(collection);
4819
5118
  const params2 = this.buildParams(args);
@@ -4823,7 +5122,7 @@ var Resolver = class {
4823
5122
  const values = await this.buildFieldMutations(
4824
5123
  params2,
4825
5124
  templateInfo.template,
4826
- doc == null ? void 0 : doc._rawData
5125
+ doc?._rawData
4827
5126
  );
4828
5127
  await this.database.put(
4829
5128
  realPath,
@@ -4844,9 +5143,10 @@ var Resolver = class {
4844
5143
  const values = {
4845
5144
  ...oldDoc,
4846
5145
  ...await this.buildFieldMutations(
5146
+ // @ts-ignore FIXME: failing on unknown, which we don't need to know because it's recursive
4847
5147
  templateParams,
4848
5148
  template,
4849
- doc == null ? void 0 : doc._rawData
5149
+ doc?._rawData
4850
5150
  ),
4851
5151
  _template: lastItem(template.namespace)
4852
5152
  };
@@ -4857,17 +5157,25 @@ var Resolver = class {
4857
5157
  return this.getDocument(realPath);
4858
5158
  }
4859
5159
  const params = await this.buildObjectMutations(
5160
+ //@ts-ignore
4860
5161
  isCollectionSpecific ? args.params : args.params[collection.name],
4861
5162
  collection,
4862
- doc == null ? void 0 : doc._rawData
5163
+ doc?._rawData
5164
+ );
5165
+ await this.database.put(
5166
+ realPath,
5167
+ { ...oldDoc, ...params },
5168
+ collection.name
4863
5169
  );
4864
- await this.database.put(realPath, { ...oldDoc, ...params }, collection.name);
4865
5170
  return this.getDocument(realPath);
4866
5171
  };
5172
+ /**
5173
+ * Returns top-level fields which are not defined in the collection, so their
5174
+ * values are not eliminated from Tina when new values are saved
5175
+ */
4867
5176
  this.resolveLegacyValues = (oldDoc, collection) => {
4868
5177
  const legacyValues = {};
4869
5178
  Object.entries(oldDoc).forEach(([key, value]) => {
4870
- var _a;
4871
5179
  const reservedKeys = [
4872
5180
  "$_body",
4873
5181
  "_collection",
@@ -4880,7 +5188,7 @@ var Resolver = class {
4880
5188
  return;
4881
5189
  }
4882
5190
  if (oldDoc._template && collection.templates) {
4883
- const template = (_a = collection.templates) == null ? void 0 : _a.find(
5191
+ const template = collection.templates?.find(
4884
5192
  ({ name }) => name === oldDoc._template
4885
5193
  );
4886
5194
  if (template) {
@@ -4927,7 +5235,7 @@ var Resolver = class {
4927
5235
  (yup3) => yup3.object({ relativePath: yup3.string().required() })
4928
5236
  );
4929
5237
  const collection = await this.tinaSchema.getCollection(collectionLookup);
4930
- let realPath = import_path3.default.join(collection == null ? void 0 : collection.path, args.relativePath);
5238
+ let realPath = import_path3.default.join(collection?.path, args.relativePath);
4931
5239
  if (isFolderCreation) {
4932
5240
  realPath = `${realPath}/.gitkeep.${collection.format || "md"}`;
4933
5241
  }
@@ -4969,6 +5277,40 @@ var Resolver = class {
4969
5277
  if (isDeletion) {
4970
5278
  const doc = await this.getDocument(realPath);
4971
5279
  await this.deleteDocument(realPath);
5280
+ if (await this.hasReferences(realPath, collection)) {
5281
+ const collRefs = await this.findReferences(realPath, collection);
5282
+ for (const [collection2, docsWithRefs] of Object.entries(collRefs)) {
5283
+ for (const [pathToDocWithRef, referencePaths] of Object.entries(
5284
+ docsWithRefs
5285
+ )) {
5286
+ let refDoc = await this.getRaw(pathToDocWithRef);
5287
+ let hasUpdate = false;
5288
+ for (const path7 of referencePaths) {
5289
+ const { object: object2, updated } = updateObjectWithJsonPath(
5290
+ refDoc,
5291
+ path7,
5292
+ realPath,
5293
+ null
5294
+ );
5295
+ refDoc = object2;
5296
+ hasUpdate = updated || hasUpdate;
5297
+ }
5298
+ if (hasUpdate) {
5299
+ const collectionWithRef = this.tinaSchema.getCollectionByFullPath(pathToDocWithRef);
5300
+ if (!collectionWithRef) {
5301
+ throw new Error(
5302
+ `Unable to find collection for ${pathToDocWithRef}`
5303
+ );
5304
+ }
5305
+ await this.database.put(
5306
+ pathToDocWithRef,
5307
+ refDoc,
5308
+ collectionWithRef.name
5309
+ );
5310
+ }
5311
+ }
5312
+ }
5313
+ }
4972
5314
  return doc;
4973
5315
  }
4974
5316
  if (isUpdateName) {
@@ -4977,20 +5319,57 @@ var Resolver = class {
4977
5319
  (yup3) => yup3.object({ params: yup3.object().required() })
4978
5320
  );
4979
5321
  assertShape(
4980
- args == null ? void 0 : args.params,
5322
+ args?.params,
4981
5323
  (yup3) => yup3.object({ relativePath: yup3.string().required() })
4982
5324
  );
4983
5325
  const doc = await this.getDocument(realPath);
4984
5326
  const newRealPath = import_path3.default.join(
4985
- collection == null ? void 0 : collection.path,
5327
+ collection?.path,
4986
5328
  args.params.relativePath
4987
5329
  );
5330
+ if (newRealPath === realPath) {
5331
+ return doc;
5332
+ }
4988
5333
  await this.database.put(newRealPath, doc._rawData, collection.name);
4989
5334
  await this.deleteDocument(realPath);
5335
+ const collRefs = await this.findReferences(realPath, collection);
5336
+ for (const [collection2, docsWithRefs] of Object.entries(collRefs)) {
5337
+ for (const [pathToDocWithRef, referencePaths] of Object.entries(
5338
+ docsWithRefs
5339
+ )) {
5340
+ let docWithRef = await this.getRaw(pathToDocWithRef);
5341
+ let hasUpdate = false;
5342
+ for (const path7 of referencePaths) {
5343
+ const { object: object2, updated } = updateObjectWithJsonPath(
5344
+ docWithRef,
5345
+ path7,
5346
+ realPath,
5347
+ newRealPath
5348
+ );
5349
+ docWithRef = object2;
5350
+ hasUpdate = updated || hasUpdate;
5351
+ }
5352
+ if (hasUpdate) {
5353
+ const collectionWithRef = this.tinaSchema.getCollectionByFullPath(pathToDocWithRef);
5354
+ if (!collectionWithRef) {
5355
+ throw new Error(
5356
+ `Unable to find collection for ${pathToDocWithRef}`
5357
+ );
5358
+ }
5359
+ await this.database.put(
5360
+ pathToDocWithRef,
5361
+ docWithRef,
5362
+ collectionWithRef.name
5363
+ );
5364
+ }
5365
+ }
5366
+ }
4990
5367
  return this.getDocument(newRealPath);
4991
5368
  }
4992
5369
  if (alreadyExists === false) {
4993
- throw new Error(`Unable to update document, ${realPath} does not exist`);
5370
+ throw new Error(
5371
+ `Unable to update document, ${realPath} does not exist`
5372
+ );
4994
5373
  }
4995
5374
  return this.updateResolveDocument({
4996
5375
  collection,
@@ -5000,7 +5379,10 @@ var Resolver = class {
5000
5379
  isCollectionSpecific
5001
5380
  });
5002
5381
  } else {
5003
- return this.getDocument(realPath);
5382
+ return this.getDocument(realPath, {
5383
+ collection,
5384
+ checkReferences: true
5385
+ });
5004
5386
  }
5005
5387
  };
5006
5388
  this.resolveCollectionConnections = async ({ ids }) => {
@@ -5037,6 +5419,7 @@ var Resolver = class {
5037
5419
  },
5038
5420
  collection: referencedCollection,
5039
5421
  hydrator: (path7) => path7
5422
+ // just return the path
5040
5423
  }
5041
5424
  );
5042
5425
  const { edges } = resolvedCollectionConnection;
@@ -5104,8 +5487,83 @@ var Resolver = class {
5104
5487
  }
5105
5488
  };
5106
5489
  };
5490
+ /**
5491
+ * Checks if a document has references to it
5492
+ * @param id The id of the document to check for references
5493
+ * @param c The collection to check for references
5494
+ * @returns true if the document has references, false otherwise
5495
+ */
5496
+ this.hasReferences = async (id, c) => {
5497
+ let count = 0;
5498
+ await this.database.query(
5499
+ {
5500
+ collection: c.name,
5501
+ filterChain: makeFilterChain({
5502
+ conditions: [
5503
+ {
5504
+ filterPath: REFS_REFERENCE_FIELD,
5505
+ filterExpression: {
5506
+ _type: "string",
5507
+ _list: false,
5508
+ eq: id
5509
+ }
5510
+ }
5511
+ ]
5512
+ }),
5513
+ sort: REFS_COLLECTIONS_SORT_KEY
5514
+ },
5515
+ (refId) => {
5516
+ count++;
5517
+ return refId;
5518
+ }
5519
+ );
5520
+ if (count) {
5521
+ return true;
5522
+ }
5523
+ return false;
5524
+ };
5525
+ /**
5526
+ * Finds references to a document
5527
+ * @param id the id of the document to find references to
5528
+ * @param c the collection to find references in
5529
+ * @returns a map of references to the document
5530
+ */
5531
+ this.findReferences = async (id, c) => {
5532
+ const references = {};
5533
+ await this.database.query(
5534
+ {
5535
+ collection: c.name,
5536
+ filterChain: makeFilterChain({
5537
+ conditions: [
5538
+ {
5539
+ filterPath: REFS_REFERENCE_FIELD,
5540
+ filterExpression: {
5541
+ _type: "string",
5542
+ _list: false,
5543
+ eq: id
5544
+ }
5545
+ }
5546
+ ]
5547
+ }),
5548
+ sort: REFS_COLLECTIONS_SORT_KEY
5549
+ },
5550
+ (refId, rawItem) => {
5551
+ if (!references[c.name]) {
5552
+ references[c.name] = {};
5553
+ }
5554
+ if (!references[c.name][refId]) {
5555
+ references[c.name][refId] = [];
5556
+ }
5557
+ const referencePath = rawItem?.[REFS_PATH_FIELD];
5558
+ if (referencePath) {
5559
+ references[c.name][refId].push(referencePath);
5560
+ }
5561
+ return refId;
5562
+ }
5563
+ );
5564
+ return references;
5565
+ };
5107
5566
  this.buildFieldMutations = async (fieldParams, template, existingData) => {
5108
- var _a;
5109
5567
  const accum = {};
5110
5568
  for (const passwordField of template.fields.filter(
5111
5569
  (f) => f.type === "password"
@@ -5148,7 +5606,7 @@ var Resolver = class {
5148
5606
  accum[fieldName] = await this.buildObjectMutations(
5149
5607
  fieldValue,
5150
5608
  field,
5151
- existingData == null ? void 0 : existingData[fieldName]
5609
+ existingData?.[fieldName]
5152
5610
  );
5153
5611
  break;
5154
5612
  case "password":
@@ -5167,12 +5625,12 @@ var Resolver = class {
5167
5625
  } else {
5168
5626
  accum[fieldName] = {
5169
5627
  ...fieldValue,
5170
- value: (_a = existingData == null ? void 0 : existingData[fieldName]) == null ? void 0 : _a["value"]
5628
+ value: existingData?.[fieldName]?.["value"]
5171
5629
  };
5172
5630
  }
5173
5631
  break;
5174
5632
  case "rich-text":
5175
- accum[fieldName] = (0, import_mdx.stringifyMDX)(
5633
+ accum[fieldName] = (0, import_mdx.serializeMDX)(
5176
5634
  fieldValue,
5177
5635
  field,
5178
5636
  (fieldValue2) => resolveMediaCloudToRelative(
@@ -5191,6 +5649,27 @@ var Resolver = class {
5191
5649
  }
5192
5650
  return accum;
5193
5651
  };
5652
+ /**
5653
+ * A mutation looks nearly identical between updateDocument:
5654
+ * ```graphql
5655
+ * updateDocument(collection: $collection,relativePath: $path, params: {
5656
+ * post: {
5657
+ * title: "Hello, World"
5658
+ * }
5659
+ * })`
5660
+ * ```
5661
+ * and `updatePostDocument`:
5662
+ * ```graphql
5663
+ * updatePostDocument(relativePath: $path, params: {
5664
+ * title: "Hello, World"
5665
+ * })
5666
+ * ```
5667
+ * The problem here is that we don't know whether the payload came from `updateDocument`
5668
+ * or `updatePostDocument` (we could, but for now it's easier not to pipe those details through),
5669
+ * But we do know that when given a `args.collection` value, we can assume that
5670
+ * this was a `updateDocument` request, and thus - should grab the data
5671
+ * from the corresponding field name in the key
5672
+ */
5194
5673
  this.buildParams = (args) => {
5195
5674
  try {
5196
5675
  assertShape(
@@ -5258,8 +5737,129 @@ var resolveDateInput = (value) => {
5258
5737
  return date;
5259
5738
  };
5260
5739
 
5261
- // src/resolve.ts
5262
- var import_lodash4 = __toESM(require("lodash.set"));
5740
+ // src/resolver/auth-fields.ts
5741
+ var import_compat = require("es-toolkit/compat");
5742
+ async function getUserDocumentContext(tinaSchema, resolver) {
5743
+ const collection = tinaSchema.getCollections().find((c) => c.isAuthCollection);
5744
+ if (!collection) {
5745
+ throw new Error("Auth collection not found");
5746
+ }
5747
+ const userFields = mapUserFields(collection, ["_rawData"]);
5748
+ if (!userFields.length) {
5749
+ throw new Error(`No user field found in collection ${collection.name}`);
5750
+ }
5751
+ if (userFields.length > 1) {
5752
+ throw new Error(
5753
+ `Multiple user fields found in collection ${collection.name}`
5754
+ );
5755
+ }
5756
+ const userField = userFields[0];
5757
+ const realPath = `${collection.path}/index.json`;
5758
+ const userDoc = await resolver.getDocument(realPath);
5759
+ const users = get(userDoc, userField.path);
5760
+ if (!users) {
5761
+ throw new Error("No users found");
5762
+ }
5763
+ return { collection, userField, users, userDoc, realPath };
5764
+ }
5765
+ function findUserInCollection(users, userField, userSub) {
5766
+ const { idFieldName } = userField;
5767
+ if (!idFieldName) {
5768
+ throw new Error("No uid field found on user field");
5769
+ }
5770
+ return users.find((u) => u[idFieldName] === userSub) || null;
5771
+ }
5772
+ async function handleAuthenticate({
5773
+ tinaSchema,
5774
+ resolver,
5775
+ sub,
5776
+ password,
5777
+ ctxUser
5778
+ }) {
5779
+ const userSub = sub || ctxUser?.sub;
5780
+ const { userField, users } = await getUserDocumentContext(
5781
+ tinaSchema,
5782
+ resolver
5783
+ );
5784
+ const user = findUserInCollection(users, userField, userSub);
5785
+ if (!user) {
5786
+ return null;
5787
+ }
5788
+ const { passwordFieldName } = userField;
5789
+ const saltedHash = get(user, [passwordFieldName || "", "value"]);
5790
+ if (!saltedHash) {
5791
+ throw new Error("No password field found on user field");
5792
+ }
5793
+ const matches = await checkPasswordHash({
5794
+ saltedHash,
5795
+ password
5796
+ });
5797
+ return matches ? user : null;
5798
+ }
5799
+ async function handleAuthorize({
5800
+ tinaSchema,
5801
+ resolver,
5802
+ sub,
5803
+ ctxUser
5804
+ }) {
5805
+ const userSub = sub || ctxUser?.sub;
5806
+ const { userField, users } = await getUserDocumentContext(
5807
+ tinaSchema,
5808
+ resolver
5809
+ );
5810
+ const user = findUserInCollection(users, userField, userSub);
5811
+ return user ? user : null;
5812
+ }
5813
+ async function handleUpdatePassword({
5814
+ tinaSchema,
5815
+ resolver,
5816
+ password,
5817
+ ctxUser
5818
+ }) {
5819
+ if (!ctxUser?.sub) {
5820
+ throw new Error("Not authorized");
5821
+ }
5822
+ if (!password) {
5823
+ throw new Error("No password provided");
5824
+ }
5825
+ const { collection, userField, users, realPath } = await getUserDocumentContext(tinaSchema, resolver);
5826
+ const { idFieldName, passwordFieldName } = userField;
5827
+ const user = users.find((u) => u[idFieldName] === ctxUser.sub);
5828
+ if (!user) {
5829
+ throw new Error("Not authorized");
5830
+ }
5831
+ user[passwordFieldName] = {
5832
+ value: password,
5833
+ passwordChangeRequired: false
5834
+ };
5835
+ const params = {};
5836
+ (0, import_compat.set)(
5837
+ params,
5838
+ userField.path.slice(1),
5839
+ // remove _rawData from users path
5840
+ users.map((u) => {
5841
+ if (user[idFieldName] === u[idFieldName]) {
5842
+ return user;
5843
+ }
5844
+ return {
5845
+ // don't overwrite other users' passwords
5846
+ ...u,
5847
+ [passwordFieldName]: {
5848
+ ...u[passwordFieldName],
5849
+ value: ""
5850
+ }
5851
+ };
5852
+ })
5853
+ );
5854
+ await resolver.updateResolveDocument({
5855
+ collection,
5856
+ args: { params },
5857
+ realPath,
5858
+ isCollectionSpecific: true,
5859
+ isAddPendingDocument: false
5860
+ });
5861
+ return true;
5862
+ }
5263
5863
 
5264
5864
  // src/error.ts
5265
5865
  var import_graphql4 = require("graphql");
@@ -5281,9 +5881,8 @@ var resolve = async ({
5281
5881
  isAudit,
5282
5882
  ctxUser
5283
5883
  }) => {
5284
- var _a;
5285
5884
  try {
5286
- const verboseValue = verbose != null ? verbose : true;
5885
+ const verboseValue = verbose ?? true;
5287
5886
  const graphQLSchemaAst = await database.getGraphQLSchema();
5288
5887
  if (!graphQLSchemaAst) {
5289
5888
  throw new import_graphql5.GraphQLError("GraphQL schema not found");
@@ -5291,8 +5890,11 @@ var resolve = async ({
5291
5890
  const graphQLSchema = (0, import_graphql5.buildASTSchema)(graphQLSchemaAst);
5292
5891
  const tinaConfig = await database.getTinaSchema();
5293
5892
  const tinaSchema = await createSchema({
5893
+ // TODO: please update all the types to import from @tinacms/schema-tools
5894
+ // @ts-ignore
5294
5895
  schema: tinaConfig,
5295
- flags: (_a = tinaConfig == null ? void 0 : tinaConfig.meta) == null ? void 0 : _a.flags
5896
+ // @ts-ignore
5897
+ flags: tinaConfig?.meta?.flags
5296
5898
  });
5297
5899
  const resolver = createResolver({
5298
5900
  config,
@@ -5308,8 +5910,7 @@ var resolve = async ({
5308
5910
  database
5309
5911
  },
5310
5912
  typeResolver: async (source, _args, info) => {
5311
- if (source.__typename)
5312
- return source.__typename;
5913
+ if (source.__typename) return source.__typename;
5313
5914
  const namedType = (0, import_graphql5.getNamedType)(info.returnType).toString();
5314
5915
  const lookup = await database.getLookup(namedType);
5315
5916
  if (lookup.resolveType === "unionData") {
@@ -5318,7 +5919,6 @@ var resolve = async ({
5318
5919
  throw new Error(`Unable to find lookup key for ${namedType}`);
5319
5920
  },
5320
5921
  fieldResolver: async (source = {}, _args = {}, _context, info) => {
5321
- var _a2, _b, _c, _d;
5322
5922
  try {
5323
5923
  const args = JSON.parse(JSON.stringify(_args));
5324
5924
  const returnType = (0, import_graphql5.getNamedType)(info.returnType).toString();
@@ -5335,8 +5935,7 @@ var resolve = async ({
5335
5935
  );
5336
5936
  const hasDocuments2 = collectionNode2.selectionSet.selections.find(
5337
5937
  (x) => {
5338
- var _a3;
5339
- return ((_a3 = x == null ? void 0 : x.name) == null ? void 0 : _a3.value) === "documents";
5938
+ return x?.name?.value === "documents";
5340
5939
  }
5341
5940
  );
5342
5941
  return tinaSchema.getCollections().map((collection) => {
@@ -5352,8 +5951,7 @@ var resolve = async ({
5352
5951
  );
5353
5952
  const hasDocuments = collectionNode.selectionSet.selections.find(
5354
5953
  (x) => {
5355
- var _a3;
5356
- return ((_a3 = x == null ? void 0 : x.name) == null ? void 0 : _a3.value) === "documents";
5954
+ return x?.name?.value === "documents";
5357
5955
  }
5358
5956
  );
5359
5957
  return resolver.resolveCollection(
@@ -5371,123 +5969,42 @@ var resolve = async ({
5371
5969
  );
5372
5970
  }
5373
5971
  }
5374
- if (info.fieldName === "authenticate" || info.fieldName === "authorize") {
5375
- const sub = args.sub || (ctxUser == null ? void 0 : ctxUser.sub);
5376
- const collection = tinaSchema.getCollections().find((c) => c.isAuthCollection);
5377
- if (!collection) {
5378
- throw new Error("Auth collection not found");
5379
- }
5380
- const userFields = mapUserFields(collection, ["_rawData"]);
5381
- if (!userFields.length) {
5382
- throw new Error(
5383
- `No user field found in collection ${collection.name}`
5384
- );
5385
- }
5386
- if (userFields.length > 1) {
5387
- throw new Error(
5388
- `Multiple user fields found in collection ${collection.name}`
5389
- );
5390
- }
5391
- const userField = userFields[0];
5392
- const realPath = `${collection.path}/index.json`;
5393
- const userDoc = await resolver.getDocument(realPath);
5394
- const users = get(userDoc, userField.path);
5395
- if (!users) {
5396
- throw new Error("No users found");
5397
- }
5398
- const { idFieldName, passwordFieldName } = userField;
5399
- if (!idFieldName) {
5400
- throw new Error("No uid field found on user field");
5401
- }
5402
- const user = users.find((u) => u[idFieldName] === sub);
5403
- if (!user) {
5404
- return null;
5405
- }
5406
- if (info.fieldName === "authenticate") {
5407
- const saltedHash = get(user, [passwordFieldName || "", "value"]);
5408
- if (!saltedHash) {
5409
- throw new Error("No password field found on user field");
5410
- }
5411
- const matches = await checkPasswordHash({
5412
- saltedHash,
5413
- password: args.password
5414
- });
5415
- if (matches) {
5416
- return user;
5417
- }
5418
- return null;
5419
- }
5420
- return user;
5972
+ if (info.fieldName === "authenticate") {
5973
+ return handleAuthenticate({
5974
+ tinaSchema,
5975
+ resolver,
5976
+ sub: args.sub,
5977
+ password: args.password,
5978
+ info,
5979
+ ctxUser
5980
+ });
5981
+ }
5982
+ if (info.fieldName === "authorize") {
5983
+ return handleAuthorize({
5984
+ tinaSchema,
5985
+ resolver,
5986
+ sub: args.sub,
5987
+ info,
5988
+ ctxUser
5989
+ });
5421
5990
  }
5422
5991
  if (info.fieldName === "updatePassword") {
5423
- if (!(ctxUser == null ? void 0 : ctxUser.sub)) {
5424
- throw new Error("Not authorized");
5425
- }
5426
- if (!args.password) {
5427
- throw new Error("No password provided");
5428
- }
5429
- const collection = tinaSchema.getCollections().find((c) => c.isAuthCollection);
5430
- if (!collection) {
5431
- throw new Error("Auth collection not found");
5432
- }
5433
- const userFields = mapUserFields(collection, ["_rawData"]);
5434
- if (!userFields.length) {
5435
- throw new Error(
5436
- `No user field found in collection ${collection.name}`
5437
- );
5438
- }
5439
- if (userFields.length > 1) {
5440
- throw new Error(
5441
- `Multiple user fields found in collection ${collection.name}`
5442
- );
5443
- }
5444
- const userField = userFields[0];
5445
- const realPath = `${collection.path}/index.json`;
5446
- const userDoc = await resolver.getDocument(realPath);
5447
- const users = get(userDoc, userField.path);
5448
- if (!users) {
5449
- throw new Error("No users found");
5450
- }
5451
- const { idFieldName, passwordFieldName } = userField;
5452
- const user = users.find((u) => u[idFieldName] === ctxUser.sub);
5453
- if (!user) {
5454
- throw new Error("Not authorized");
5455
- }
5456
- user[passwordFieldName] = {
5457
- value: args.password,
5458
- passwordChangeRequired: false
5459
- };
5460
- const params = {};
5461
- (0, import_lodash4.default)(
5462
- params,
5463
- userField.path.slice(1),
5464
- users.map((u) => {
5465
- if (user[idFieldName] === u[idFieldName]) {
5466
- return user;
5467
- }
5468
- return {
5469
- ...u,
5470
- [passwordFieldName]: {
5471
- ...u[passwordFieldName],
5472
- value: ""
5473
- }
5474
- };
5475
- })
5476
- );
5477
- await resolver.updateResolveDocument({
5478
- collection,
5479
- args: { params },
5480
- realPath,
5481
- isCollectionSpecific: true,
5482
- isAddPendingDocument: false
5992
+ return handleUpdatePassword({
5993
+ tinaSchema,
5994
+ resolver,
5995
+ password: args.password,
5996
+ info,
5997
+ ctxUser
5483
5998
  });
5484
- return true;
5485
5999
  }
5486
6000
  if (!lookup) {
5487
6001
  return value;
5488
6002
  }
5489
6003
  const isCreation = lookup[info.fieldName] === "create";
5490
6004
  switch (lookup.resolveType) {
6005
+ /**
6006
+ * `node(id: $id)`
6007
+ */
5491
6008
  case "nodeDocument":
5492
6009
  assertShape(
5493
6010
  args,
@@ -5498,7 +6015,7 @@ var resolve = async ({
5498
6015
  if (typeof value === "string" && value !== "") {
5499
6016
  return resolver.getDocument(value);
5500
6017
  }
5501
- if ((args == null ? void 0 : args.collection) && info.fieldName === "addPendingDocument") {
6018
+ if (args?.collection && info.fieldName === "addPendingDocument") {
5502
6019
  return resolver.resolveDocument({
5503
6020
  args: { ...args, params: {} },
5504
6021
  collection: args.collection,
@@ -5519,15 +6036,19 @@ var resolve = async ({
5519
6036
  collection: args.collection,
5520
6037
  isMutation,
5521
6038
  isCreation,
6039
+ // Right now this is the only case for deletion
5522
6040
  isDeletion: info.fieldName === "deleteDocument",
5523
6041
  isFolderCreation: info.fieldName === "createFolder",
5524
- isUpdateName: Boolean((_a2 = args == null ? void 0 : args.params) == null ? void 0 : _a2.relativePath),
6042
+ isUpdateName: Boolean(args?.params?.relativePath),
5525
6043
  isAddPendingDocument: false,
5526
6044
  isCollectionSpecific: false
5527
6045
  });
5528
6046
  return result;
5529
6047
  }
5530
6048
  return value;
6049
+ /**
6050
+ * eg `getMovieDocument.data.actors`
6051
+ */
5531
6052
  case "multiCollectionDocumentList":
5532
6053
  if (Array.isArray(value)) {
5533
6054
  return {
@@ -5537,9 +6058,17 @@ var resolve = async ({
5537
6058
  })
5538
6059
  };
5539
6060
  }
5540
- if (info.fieldName === "documents" && (value == null ? void 0 : value.collection) && (value == null ? void 0 : value.hasDocuments)) {
6061
+ if (info.fieldName === "documents" && value?.collection && value?.hasDocuments) {
5541
6062
  let filter = args.filter;
5542
- if (typeof (args == null ? void 0 : args.filter) !== "undefined" && (args == null ? void 0 : args.filter) !== null && typeof ((_b = value == null ? void 0 : value.collection) == null ? void 0 : _b.name) === "string" && Object.keys(args.filter).includes((_c = value == null ? void 0 : value.collection) == null ? void 0 : _c.name) && typeof args.filter[(_d = value == null ? void 0 : value.collection) == null ? void 0 : _d.name] !== "undefined") {
6063
+ if (
6064
+ // 1. Make sure that the filter exists
6065
+ typeof args?.filter !== "undefined" && args?.filter !== null && // 2. Make sure that the collection name exists
6066
+ // @ts-ignore
6067
+ typeof value?.collection?.name === "string" && // 3. Make sure that the collection name is in the filter and is not undefined
6068
+ // @ts-ignore
6069
+ Object.keys(args.filter).includes(value?.collection?.name) && // @ts-ignore
6070
+ typeof args.filter[value?.collection?.name] !== "undefined"
6071
+ ) {
5543
6072
  filter = args.filter[value.collection.name];
5544
6073
  }
5545
6074
  return resolver.resolveCollectionConnection({
@@ -5547,12 +6076,20 @@ var resolve = async ({
5547
6076
  ...args,
5548
6077
  filter
5549
6078
  },
6079
+ // @ts-ignore
5550
6080
  collection: value.collection
5551
6081
  });
5552
6082
  }
5553
6083
  throw new Error(
5554
6084
  `Expected an array for result of ${info.fieldName} at ${info.path}`
5555
6085
  );
6086
+ /**
6087
+ * Collections-specific getter
6088
+ * eg. `getPostDocument`/`createPostDocument`/`updatePostDocument`
6089
+ *
6090
+ * if coming from a query result
6091
+ * the field will be `node`
6092
+ */
5556
6093
  case "collectionDocument": {
5557
6094
  if (value) {
5558
6095
  return value;
@@ -5567,11 +6104,32 @@ var resolve = async ({
5567
6104
  });
5568
6105
  return result;
5569
6106
  }
6107
+ /**
6108
+ * Collections-specific list getter
6109
+ * eg. `getPageList`
6110
+ */
5570
6111
  case "collectionDocumentList":
5571
6112
  return resolver.resolveCollectionConnection({
5572
6113
  args,
5573
6114
  collection: tinaSchema.getCollection(lookup.collection)
5574
6115
  });
6116
+ /**
6117
+ * A polymorphic data set, it can be from a document's data
6118
+ * of any nested object which can be one of many shapes
6119
+ *
6120
+ * ```graphql
6121
+ * getPostDocument(relativePath: $relativePath) {
6122
+ * data {...} <- this part
6123
+ * }
6124
+ * ```
6125
+ * ```graphql
6126
+ * getBlockDocument(relativePath: $relativePath) {
6127
+ * data {
6128
+ * blocks {...} <- or this part
6129
+ * }
6130
+ * }
6131
+ * ```
6132
+ */
5575
6133
  case "unionData":
5576
6134
  if (!value) {
5577
6135
  if (args.relativePath) {
@@ -5636,8 +6194,7 @@ var TinaLevelClient = class extends import_many_level.ManyLevelGuest {
5636
6194
  this.port = port || 9e3;
5637
6195
  }
5638
6196
  openConnection() {
5639
- if (this._connected)
5640
- return;
6197
+ if (this._connected) return;
5641
6198
  const socket = (0, import_net.connect)(this.port);
5642
6199
  (0, import_readable_stream.pipeline)(socket, this.createRpcStream(), socket, () => {
5643
6200
  this._connected = false;
@@ -5647,15 +6204,15 @@ var TinaLevelClient = class extends import_many_level.ManyLevelGuest {
5647
6204
  };
5648
6205
 
5649
6206
  // src/database/index.ts
5650
- var import_node_path = __toESM(require("path"));
6207
+ var import_node_path = __toESM(require("node:path"));
5651
6208
  var import_graphql6 = require("graphql");
5652
6209
  var import_micromatch2 = __toESM(require("micromatch"));
5653
6210
  var import_js_sha12 = __toESM(require("js-sha1"));
5654
- var import_lodash5 = __toESM(require("lodash.set"));
6211
+ var import_compat2 = require("es-toolkit/compat");
5655
6212
  var createLocalDatabase = (config) => {
5656
- const level = new TinaLevelClient(config == null ? void 0 : config.port);
6213
+ const level = new TinaLevelClient(config?.port);
5657
6214
  level.openConnection();
5658
- const fsBridge = new FilesystemBridge((config == null ? void 0 : config.rootPath) || process.cwd());
6215
+ const fsBridge = new FilesystemBridge(config?.rootPath || process.cwd());
5659
6216
  return new Database({
5660
6217
  bridge: fsBridge,
5661
6218
  ...config || {},
@@ -5728,7 +6285,7 @@ var Database = class {
5728
6285
  );
5729
6286
  }
5730
6287
  const metadata = await metadataLevel.get(`metadata_${key}`);
5731
- return metadata == null ? void 0 : metadata.value;
6288
+ return metadata?.value;
5732
6289
  };
5733
6290
  this.setMetadata = async (key, value) => {
5734
6291
  await this.initLevel();
@@ -5750,14 +6307,14 @@ var Database = class {
5750
6307
  let level = this.contentLevel;
5751
6308
  if (this.appLevel) {
5752
6309
  collection = await this.collectionForPath(filepath);
5753
- if (collection == null ? void 0 : collection.isDetached) {
6310
+ if (collection?.isDetached) {
5754
6311
  level = this.appLevel.sublevel(collection.name, SUBLEVEL_OPTIONS);
5755
6312
  }
5756
6313
  }
5757
6314
  const contentObject = await level.sublevel(
5758
6315
  CONTENT_ROOT_PREFIX,
5759
6316
  SUBLEVEL_OPTIONS
5760
- ).get((0, import_schema_tools3.normalizePath)(filepath));
6317
+ ).get((0, import_schema_tools4.normalizePath)(filepath));
5761
6318
  if (!contentObject) {
5762
6319
  throw new NotFoundError(`Unable to find record ${filepath}`);
5763
6320
  }
@@ -5781,9 +6338,10 @@ var Database = class {
5781
6338
  collection
5782
6339
  );
5783
6340
  const indexDefinitions = await this.getIndexDefinitions(this.contentLevel);
5784
- const collectionIndexDefinitions = indexDefinitions == null ? void 0 : indexDefinitions[collection.name];
5785
- const normalizedPath = (0, import_schema_tools3.normalizePath)(filepath);
5786
- if (!(collection == null ? void 0 : collection.isDetached)) {
6341
+ const collectionIndexDefinitions = indexDefinitions?.[collection.name];
6342
+ const collectionReferences = (await this.getCollectionReferences())?.[collection.name];
6343
+ const normalizedPath = (0, import_schema_tools4.normalizePath)(filepath);
6344
+ if (!collection?.isDetached) {
5787
6345
  if (this.bridge) {
5788
6346
  await this.bridge.put(normalizedPath, stringifiedFile);
5789
6347
  }
@@ -5801,7 +6359,7 @@ var Database = class {
5801
6359
  }
5802
6360
  }
5803
6361
  let level = this.contentLevel;
5804
- if (collection == null ? void 0 : collection.isDetached) {
6362
+ if (collection?.isDetached) {
5805
6363
  level = this.appLevel.sublevel(collection.name, SUBLEVEL_OPTIONS);
5806
6364
  }
5807
6365
  const folderTreeBuilder = new FolderTreeBuilder();
@@ -5810,17 +6368,26 @@ var Database = class {
5810
6368
  let delOps = [];
5811
6369
  if (!isGitKeep(normalizedPath, collection)) {
5812
6370
  putOps = [
6371
+ ...makeRefOpsForDocument(
6372
+ normalizedPath,
6373
+ collection?.name,
6374
+ collectionReferences,
6375
+ dataFields,
6376
+ "put",
6377
+ level
6378
+ ),
5813
6379
  ...makeIndexOpsForDocument(
5814
6380
  normalizedPath,
5815
- collection == null ? void 0 : collection.name,
6381
+ collection?.name,
5816
6382
  collectionIndexDefinitions,
5817
6383
  dataFields,
5818
6384
  "put",
5819
6385
  level
5820
6386
  ),
6387
+ // folder indices
5821
6388
  ...makeIndexOpsForDocument(
5822
6389
  normalizedPath,
5823
- `${collection == null ? void 0 : collection.name}_${folderKey}`,
6390
+ `${collection?.name}_${folderKey}`,
5824
6391
  collectionIndexDefinitions,
5825
6392
  dataFields,
5826
6393
  "put",
@@ -5832,17 +6399,26 @@ var Database = class {
5832
6399
  SUBLEVEL_OPTIONS
5833
6400
  ).get(normalizedPath);
5834
6401
  delOps = existingItem ? [
6402
+ ...makeRefOpsForDocument(
6403
+ normalizedPath,
6404
+ collection?.name,
6405
+ collectionReferences,
6406
+ existingItem,
6407
+ "del",
6408
+ level
6409
+ ),
5835
6410
  ...makeIndexOpsForDocument(
5836
6411
  normalizedPath,
5837
- collection == null ? void 0 : collection.name,
6412
+ collection?.name,
5838
6413
  collectionIndexDefinitions,
5839
6414
  existingItem,
5840
6415
  "del",
5841
6416
  level
5842
6417
  ),
6418
+ // folder indices
5843
6419
  ...makeIndexOpsForDocument(
5844
6420
  normalizedPath,
5845
- `${collection == null ? void 0 : collection.name}_${folderKey}`,
6421
+ `${collection?.name}_${folderKey}`,
5846
6422
  collectionIndexDefinitions,
5847
6423
  existingItem,
5848
6424
  "del",
@@ -5866,7 +6442,6 @@ var Database = class {
5866
6442
  await level.batch(ops);
5867
6443
  };
5868
6444
  this.put = async (filepath, data, collectionName) => {
5869
- var _a, _b;
5870
6445
  await this.initLevel();
5871
6446
  try {
5872
6447
  if (SYSTEM_FILES.includes(filepath)) {
@@ -5877,15 +6452,16 @@ var Database = class {
5877
6452
  const indexDefinitions = await this.getIndexDefinitions(
5878
6453
  this.contentLevel
5879
6454
  );
5880
- collectionIndexDefinitions = indexDefinitions == null ? void 0 : indexDefinitions[collectionName];
6455
+ collectionIndexDefinitions = indexDefinitions?.[collectionName];
5881
6456
  }
5882
- const normalizedPath = (0, import_schema_tools3.normalizePath)(filepath);
6457
+ const collectionReferences = (await this.getCollectionReferences())?.[collectionName];
6458
+ const normalizedPath = (0, import_schema_tools4.normalizePath)(filepath);
5883
6459
  const dataFields = await this.formatBodyOnPayload(filepath, data);
5884
6460
  const collection = await this.collectionForPath(filepath);
5885
6461
  if (!collection) {
5886
6462
  throw new import_graphql6.GraphQLError(`Unable to find collection for ${filepath}.`);
5887
6463
  }
5888
- if (((_a = collection.match) == null ? void 0 : _a.exclude) || ((_b = collection.match) == null ? void 0 : _b.include)) {
6464
+ if (collection.match?.exclude || collection.match?.include) {
5889
6465
  const matches = this.tinaSchema.getMatches({ collection });
5890
6466
  const match = import_micromatch2.default.isMatch(filepath, matches);
5891
6467
  if (!match) {
@@ -5899,7 +6475,7 @@ var Database = class {
5899
6475
  const stringifiedFile = filepath.endsWith(
5900
6476
  `.gitkeep.${collection.format || "md"}`
5901
6477
  ) ? "" : await this.stringifyFile(filepath, dataFields, collection);
5902
- if (!(collection == null ? void 0 : collection.isDetached)) {
6478
+ if (!collection?.isDetached) {
5903
6479
  if (this.bridge) {
5904
6480
  await this.bridge.put(normalizedPath, stringifiedFile);
5905
6481
  }
@@ -5921,11 +6497,19 @@ var Database = class {
5921
6497
  filepath,
5922
6498
  collection.path || ""
5923
6499
  );
5924
- const level = (collection == null ? void 0 : collection.isDetached) ? this.appLevel.sublevel(collection == null ? void 0 : collection.name, SUBLEVEL_OPTIONS) : this.contentLevel;
6500
+ const level = collection?.isDetached ? this.appLevel.sublevel(collection?.name, SUBLEVEL_OPTIONS) : this.contentLevel;
5925
6501
  let putOps = [];
5926
6502
  let delOps = [];
5927
6503
  if (!isGitKeep(normalizedPath, collection)) {
5928
6504
  putOps = [
6505
+ ...makeRefOpsForDocument(
6506
+ normalizedPath,
6507
+ collectionName,
6508
+ collectionReferences,
6509
+ dataFields,
6510
+ "put",
6511
+ level
6512
+ ),
5929
6513
  ...makeIndexOpsForDocument(
5930
6514
  normalizedPath,
5931
6515
  collectionName,
@@ -5934,9 +6518,10 @@ var Database = class {
5934
6518
  "put",
5935
6519
  level
5936
6520
  ),
6521
+ // folder indices
5937
6522
  ...makeIndexOpsForDocument(
5938
6523
  normalizedPath,
5939
- `${collection == null ? void 0 : collection.name}_${folderKey}`,
6524
+ `${collection?.name}_${folderKey}`,
5940
6525
  collectionIndexDefinitions,
5941
6526
  dataFields,
5942
6527
  "put",
@@ -5948,6 +6533,14 @@ var Database = class {
5948
6533
  SUBLEVEL_OPTIONS
5949
6534
  ).get(normalizedPath);
5950
6535
  delOps = existingItem ? [
6536
+ ...makeRefOpsForDocument(
6537
+ normalizedPath,
6538
+ collectionName,
6539
+ collectionReferences,
6540
+ existingItem,
6541
+ "del",
6542
+ level
6543
+ ),
5951
6544
  ...makeIndexOpsForDocument(
5952
6545
  normalizedPath,
5953
6546
  collectionName,
@@ -5956,9 +6549,10 @@ var Database = class {
5956
6549
  "del",
5957
6550
  level
5958
6551
  ),
6552
+ // folder indices
5959
6553
  ...makeIndexOpsForDocument(
5960
6554
  normalizedPath,
5961
- `${collection == null ? void 0 : collection.name}_${folderKey}`,
6555
+ `${collection?.name}_${folderKey}`,
5962
6556
  collectionIndexDefinitions,
5963
6557
  existingItem,
5964
6558
  "del",
@@ -5989,8 +6583,7 @@ var Database = class {
5989
6583
  throw new TinaFetchError(`Error in PUT for ${filepath}`, {
5990
6584
  originalError: error,
5991
6585
  file: filepath,
5992
- collection: collectionName,
5993
- stack: error.stack
6586
+ collection: collectionName
5994
6587
  });
5995
6588
  }
5996
6589
  };
@@ -6033,9 +6626,10 @@ var Database = class {
6033
6626
  aliasedData,
6034
6627
  extension,
6035
6628
  writeTemplateKey,
6629
+ //templateInfo.type === 'union',
6036
6630
  {
6037
- frontmatterFormat: collection == null ? void 0 : collection.frontmatterFormat,
6038
- frontmatterDelimiters: collection == null ? void 0 : collection.frontmatterDelimiters
6631
+ frontmatterFormat: collection?.frontmatterFormat,
6632
+ frontmatterDelimiters: collection?.frontmatterDelimiters
6039
6633
  }
6040
6634
  );
6041
6635
  };
@@ -6050,7 +6644,7 @@ var Database = class {
6050
6644
  };
6051
6645
  this.getLookup = async (returnType) => {
6052
6646
  await this.initLevel();
6053
- const lookupPath = (0, import_schema_tools3.normalizePath)(
6647
+ const lookupPath = (0, import_schema_tools4.normalizePath)(
6054
6648
  import_node_path.default.join(this.getGeneratedFolder(), `_lookup.json`)
6055
6649
  );
6056
6650
  if (!this._lookup) {
@@ -6063,7 +6657,7 @@ var Database = class {
6063
6657
  };
6064
6658
  this.getGraphQLSchema = async () => {
6065
6659
  await this.initLevel();
6066
- const graphqlPath = (0, import_schema_tools3.normalizePath)(
6660
+ const graphqlPath = (0, import_schema_tools4.normalizePath)(
6067
6661
  import_node_path.default.join(this.getGeneratedFolder(), `_graphql.json`)
6068
6662
  );
6069
6663
  return await this.contentLevel.sublevel(
@@ -6071,11 +6665,12 @@ var Database = class {
6071
6665
  SUBLEVEL_OPTIONS
6072
6666
  ).get(graphqlPath);
6073
6667
  };
6668
+ //TODO - is there a reason why the database fetches some config with "bridge.get", and some with "store.get"?
6074
6669
  this.getGraphQLSchemaFromBridge = async () => {
6075
6670
  if (!this.bridge) {
6076
6671
  throw new Error(`No bridge configured`);
6077
6672
  }
6078
- const graphqlPath = (0, import_schema_tools3.normalizePath)(
6673
+ const graphqlPath = (0, import_schema_tools4.normalizePath)(
6079
6674
  import_node_path.default.join(this.getGeneratedFolder(), `_graphql.json`)
6080
6675
  );
6081
6676
  const _graphql = await this.bridge.get(graphqlPath);
@@ -6083,7 +6678,7 @@ var Database = class {
6083
6678
  };
6084
6679
  this.getTinaSchema = async (level) => {
6085
6680
  await this.initLevel();
6086
- const schemaPath = (0, import_schema_tools3.normalizePath)(
6681
+ const schemaPath = (0, import_schema_tools4.normalizePath)(
6087
6682
  import_node_path.default.join(this.getGeneratedFolder(), `_schema.json`)
6088
6683
  );
6089
6684
  return await (level || this.contentLevel).sublevel(
@@ -6099,7 +6694,7 @@ var Database = class {
6099
6694
  const schema = existingSchema || await this.getTinaSchema(level || this.contentLevel);
6100
6695
  if (!schema) {
6101
6696
  throw new Error(
6102
- `Unable to get schema from level db: ${(0, import_schema_tools3.normalizePath)(
6697
+ `Unable to get schema from level db: ${(0, import_schema_tools4.normalizePath)(
6103
6698
  import_node_path.default.join(this.getGeneratedFolder(), `_schema.json`)
6104
6699
  )}`
6105
6700
  );
@@ -6107,6 +6702,22 @@ var Database = class {
6107
6702
  this.tinaSchema = await createSchema({ schema });
6108
6703
  return this.tinaSchema;
6109
6704
  };
6705
+ this.getCollectionReferences = async (level) => {
6706
+ if (this.collectionReferences) {
6707
+ return this.collectionReferences;
6708
+ }
6709
+ const result = {};
6710
+ const schema = await this.getSchema(level || this.contentLevel);
6711
+ const collections = schema.getCollections();
6712
+ for (const collection of collections) {
6713
+ const collectionReferences = this.tinaSchema.findReferencesFromCollection(
6714
+ collection.name
6715
+ );
6716
+ result[collection.name] = collectionReferences;
6717
+ }
6718
+ this.collectionReferences = result;
6719
+ return result;
6720
+ };
6110
6721
  this.getIndexDefinitions = async (level) => {
6111
6722
  if (!this.collectionIndexDefinitions) {
6112
6723
  await new Promise(async (resolve2, reject) => {
@@ -6116,10 +6727,53 @@ var Database = class {
6116
6727
  const collections = schema.getCollections();
6117
6728
  for (const collection of collections) {
6118
6729
  const indexDefinitions = {
6119
- [DEFAULT_COLLECTION_SORT_KEY]: { fields: [] }
6730
+ [DEFAULT_COLLECTION_SORT_KEY]: { fields: [] },
6731
+ // provide a default sort key which is the file sort
6732
+ // pseudo-index for the collection's references
6733
+ [REFS_COLLECTIONS_SORT_KEY]: {
6734
+ fields: [
6735
+ {
6736
+ name: REFS_REFERENCE_FIELD,
6737
+ type: "string",
6738
+ list: false
6739
+ },
6740
+ {
6741
+ name: REFS_PATH_FIELD,
6742
+ type: "string",
6743
+ list: false
6744
+ }
6745
+ ]
6746
+ }
6120
6747
  };
6121
- if (collection.fields) {
6122
- for (const field of collection.fields) {
6748
+ let fields = [];
6749
+ if (collection.templates) {
6750
+ const templateFieldMap = {};
6751
+ const conflictedFields = /* @__PURE__ */ new Set();
6752
+ for (const template of collection.templates) {
6753
+ for (const field of template.fields) {
6754
+ if (!templateFieldMap[field.name]) {
6755
+ templateFieldMap[field.name] = field;
6756
+ } else {
6757
+ if (templateFieldMap[field.name].type !== field.type) {
6758
+ console.warn(
6759
+ `Field ${field.name} has conflicting types in templates - skipping index`
6760
+ );
6761
+ conflictedFields.add(field.name);
6762
+ }
6763
+ }
6764
+ }
6765
+ }
6766
+ for (const conflictedField in conflictedFields) {
6767
+ delete templateFieldMap[conflictedField];
6768
+ }
6769
+ for (const field of Object.values(templateFieldMap)) {
6770
+ fields.push(field);
6771
+ }
6772
+ } else if (collection.fields) {
6773
+ fields = collection.fields;
6774
+ }
6775
+ if (fields) {
6776
+ for (const field of fields) {
6123
6777
  if (field.indexed !== void 0 && field.indexed === false || field.type === "object") {
6124
6778
  continue;
6125
6779
  }
@@ -6144,8 +6798,8 @@ var Database = class {
6144
6798
  );
6145
6799
  return {
6146
6800
  name: indexField.name,
6147
- type: field == null ? void 0 : field.type,
6148
- list: !!(field == null ? void 0 : field.list)
6801
+ type: field?.type,
6802
+ list: !!field?.list
6149
6803
  };
6150
6804
  })
6151
6805
  };
@@ -6171,7 +6825,6 @@ var Database = class {
6171
6825
  return true;
6172
6826
  };
6173
6827
  this.query = async (queryOptions, hydrator) => {
6174
- var _a;
6175
6828
  await this.initLevel();
6176
6829
  const {
6177
6830
  first,
@@ -6199,14 +6852,14 @@ var Database = class {
6199
6852
  const allIndexDefinitions = await this.getIndexDefinitions(
6200
6853
  this.contentLevel
6201
6854
  );
6202
- const indexDefinitions = allIndexDefinitions == null ? void 0 : allIndexDefinitions[collection.name];
6855
+ const indexDefinitions = allIndexDefinitions?.[collection.name];
6203
6856
  if (!indexDefinitions) {
6204
6857
  throw new Error(`No indexDefinitions for collection ${collection.name}`);
6205
6858
  }
6206
6859
  const filterChain = coerceFilterChainOperands(rawFilterChain);
6207
- const indexDefinition = sort && (indexDefinitions == null ? void 0 : indexDefinitions[sort]);
6860
+ const indexDefinition = sort && indexDefinitions?.[sort];
6208
6861
  const filterSuffixes = indexDefinition && makeFilterSuffixes(filterChain, indexDefinition);
6209
- const level = (collection == null ? void 0 : collection.isDetached) ? this.appLevel.sublevel(collection == null ? void 0 : collection.name, SUBLEVEL_OPTIONS) : this.contentLevel;
6862
+ const level = collection?.isDetached ? this.appLevel.sublevel(collection?.name, SUBLEVEL_OPTIONS) : this.contentLevel;
6210
6863
  const rootLevel = level.sublevel(
6211
6864
  CONTENT_ROOT_PREFIX,
6212
6865
  SUBLEVEL_OPTIONS
@@ -6216,17 +6869,17 @@ var Database = class {
6216
6869
  SUBLEVEL_OPTIONS
6217
6870
  ).sublevel(sort, SUBLEVEL_OPTIONS) : rootLevel;
6218
6871
  if (!query.gt && !query.gte) {
6219
- query.gte = (filterSuffixes == null ? void 0 : filterSuffixes.left) ? filterSuffixes.left : "";
6872
+ query.gte = filterSuffixes?.left ? filterSuffixes.left : "";
6220
6873
  }
6221
6874
  if (!query.lt && !query.lte) {
6222
- query.lte = (filterSuffixes == null ? void 0 : filterSuffixes.right) ? `${filterSuffixes.right}\uFFFF` : "\uFFFF";
6875
+ query.lte = filterSuffixes?.right ? `${filterSuffixes.right}\uFFFF` : "\uFFFF";
6223
6876
  }
6224
6877
  let edges = [];
6225
6878
  let startKey = "";
6226
6879
  let endKey = "";
6227
6880
  let hasPreviousPage = false;
6228
6881
  let hasNextPage = false;
6229
- const fieldsPattern = ((_a = indexDefinition == null ? void 0 : indexDefinition.fields) == null ? void 0 : _a.length) ? `${indexDefinition.fields.map((p) => `(?<${p.name}>.+)${INDEX_KEY_FIELD_SEPARATOR}`).join("")}` : "";
6882
+ const fieldsPattern = indexDefinition?.fields?.length ? `${indexDefinition.fields.map((p) => `(?<${p.name}>.+)${INDEX_KEY_FIELD_SEPARATOR}`).join("")}` : "";
6230
6883
  const valuesRegex = indexDefinition ? new RegExp(`^${fieldsPattern}(?<_filepath_>.+)`) : new RegExp(`^(?<_filepath_>.+)`);
6231
6884
  const itemFilter = makeFilter({ filterChain });
6232
6885
  const iterator = sublevel.iterator(query);
@@ -6268,29 +6921,35 @@ var Database = class {
6268
6921
  }
6269
6922
  startKey = startKey || key || "";
6270
6923
  endKey = key || "";
6271
- edges = [...edges, { cursor: key, path: filepath }];
6924
+ edges = [...edges, { cursor: key, path: filepath, value: itemRecord }];
6272
6925
  }
6273
6926
  return {
6274
- edges: await sequential(edges, async (edge) => {
6275
- try {
6276
- const node = await hydrator(edge.path);
6277
- return {
6278
- node,
6279
- cursor: btoa(edge.cursor)
6280
- };
6281
- } catch (error) {
6282
- console.log(error);
6283
- if (error instanceof Error && (!edge.path.includes(".tina/__generated__/_graphql.json") || !edge.path.includes("tina/__generated__/_graphql.json"))) {
6284
- throw new TinaQueryError({
6285
- originalError: error,
6286
- file: edge.path,
6287
- collection: collection.name,
6288
- stack: error.stack
6289
- });
6927
+ edges: await sequential(
6928
+ edges,
6929
+ async ({
6930
+ cursor,
6931
+ path: path7,
6932
+ value
6933
+ }) => {
6934
+ try {
6935
+ const node = await hydrator(path7, value);
6936
+ return {
6937
+ node,
6938
+ cursor: btoa(cursor)
6939
+ };
6940
+ } catch (error) {
6941
+ console.log(error);
6942
+ if (error instanceof Error && (!path7.includes(".tina/__generated__/_graphql.json") || !path7.includes("tina/__generated__/_graphql.json"))) {
6943
+ throw new TinaQueryError({
6944
+ originalError: error,
6945
+ file: path7,
6946
+ collection: collection.name
6947
+ });
6948
+ }
6949
+ throw error;
6290
6950
  }
6291
- throw error;
6292
6951
  }
6293
- }),
6952
+ ),
6294
6953
  pageInfo: {
6295
6954
  hasPreviousPage,
6296
6955
  hasNextPage,
@@ -6315,7 +6974,7 @@ var Database = class {
6315
6974
  try {
6316
6975
  lookup = lookupFromLockFile || JSON.parse(
6317
6976
  await this.bridge.get(
6318
- (0, import_schema_tools3.normalizePath)(
6977
+ (0, import_schema_tools4.normalizePath)(
6319
6978
  import_node_path.default.join(this.getGeneratedFolder(), "_lookup.json")
6320
6979
  )
6321
6980
  )
@@ -6340,15 +6999,15 @@ var Database = class {
6340
6999
  }
6341
7000
  const contentRootLevel = nextLevel.sublevel(CONTENT_ROOT_PREFIX, SUBLEVEL_OPTIONS);
6342
7001
  await contentRootLevel.put(
6343
- (0, import_schema_tools3.normalizePath)(import_node_path.default.join(this.getGeneratedFolder(), "_graphql.json")),
7002
+ (0, import_schema_tools4.normalizePath)(import_node_path.default.join(this.getGeneratedFolder(), "_graphql.json")),
6344
7003
  graphQLSchema
6345
7004
  );
6346
7005
  await contentRootLevel.put(
6347
- (0, import_schema_tools3.normalizePath)(import_node_path.default.join(this.getGeneratedFolder(), "_schema.json")),
7006
+ (0, import_schema_tools4.normalizePath)(import_node_path.default.join(this.getGeneratedFolder(), "_schema.json")),
6348
7007
  tinaSchema.schema
6349
7008
  );
6350
7009
  await contentRootLevel.put(
6351
- (0, import_schema_tools3.normalizePath)(import_node_path.default.join(this.getGeneratedFolder(), "_lookup.json")),
7010
+ (0, import_schema_tools4.normalizePath)(import_node_path.default.join(this.getGeneratedFolder(), "_lookup.json")),
6352
7011
  lookup
6353
7012
  );
6354
7013
  const result = await this._indexAllContent(
@@ -6414,13 +7073,14 @@ var Database = class {
6414
7073
  documentPaths,
6415
7074
  async (collection, documentPaths2) => {
6416
7075
  if (collection && !collection.isDetached) {
6417
- await _indexContent(
6418
- this,
6419
- this.contentLevel,
6420
- documentPaths2,
7076
+ await _indexContent({
7077
+ database: this,
7078
+ level: this.contentLevel,
7079
+ documentPaths: documentPaths2,
6421
7080
  enqueueOps,
6422
- collection
6423
- );
7081
+ collection,
7082
+ isPartialReindex: true
7083
+ });
6424
7084
  }
6425
7085
  }
6426
7086
  );
@@ -6436,17 +7096,18 @@ var Database = class {
6436
7096
  throw new Error(`No collection found for path: ${filepath}`);
6437
7097
  }
6438
7098
  const indexDefinitions = await this.getIndexDefinitions(this.contentLevel);
6439
- const collectionIndexDefinitions = indexDefinitions == null ? void 0 : indexDefinitions[collection.name];
7099
+ const collectionReferences = (await this.getCollectionReferences())?.[collection.name];
7100
+ const collectionIndexDefinitions = indexDefinitions?.[collection.name];
6440
7101
  let level = this.contentLevel;
6441
- if (collection == null ? void 0 : collection.isDetached) {
6442
- level = this.appLevel.sublevel(collection == null ? void 0 : collection.name, SUBLEVEL_OPTIONS);
7102
+ if (collection?.isDetached) {
7103
+ level = this.appLevel.sublevel(collection?.name, SUBLEVEL_OPTIONS);
6443
7104
  }
6444
- const itemKey = (0, import_schema_tools3.normalizePath)(filepath);
7105
+ const normalizedPath = (0, import_schema_tools4.normalizePath)(filepath);
6445
7106
  const rootSublevel = level.sublevel(
6446
7107
  CONTENT_ROOT_PREFIX,
6447
7108
  SUBLEVEL_OPTIONS
6448
7109
  );
6449
- const item = await rootSublevel.get(itemKey);
7110
+ const item = await rootSublevel.get(normalizedPath);
6450
7111
  if (item) {
6451
7112
  const folderTreeBuilder = new FolderTreeBuilder();
6452
7113
  const folderKey = folderTreeBuilder.update(
@@ -6454,16 +7115,25 @@ var Database = class {
6454
7115
  collection.path || ""
6455
7116
  );
6456
7117
  await this.contentLevel.batch([
7118
+ ...makeRefOpsForDocument(
7119
+ normalizedPath,
7120
+ collection.name,
7121
+ collectionReferences,
7122
+ item,
7123
+ "del",
7124
+ level
7125
+ ),
6457
7126
  ...makeIndexOpsForDocument(
6458
- filepath,
7127
+ normalizedPath,
6459
7128
  collection.name,
6460
7129
  collectionIndexDefinitions,
6461
7130
  item,
6462
7131
  "del",
6463
7132
  level
6464
7133
  ),
7134
+ // folder indices
6465
7135
  ...makeIndexOpsForDocument(
6466
- filepath,
7136
+ normalizedPath,
6467
7137
  `${collection.name}_${folderKey}`,
6468
7138
  collectionIndexDefinitions,
6469
7139
  item,
@@ -6472,17 +7142,17 @@ var Database = class {
6472
7142
  ),
6473
7143
  {
6474
7144
  type: "del",
6475
- key: itemKey,
7145
+ key: normalizedPath,
6476
7146
  sublevel: rootSublevel
6477
7147
  }
6478
7148
  ]);
6479
7149
  }
6480
- if (!(collection == null ? void 0 : collection.isDetached)) {
7150
+ if (!collection?.isDetached) {
6481
7151
  if (this.bridge) {
6482
- await this.bridge.delete((0, import_schema_tools3.normalizePath)(filepath));
7152
+ await this.bridge.delete(normalizedPath);
6483
7153
  }
6484
7154
  try {
6485
- await this.onDelete((0, import_schema_tools3.normalizePath)(filepath));
7155
+ await this.onDelete(normalizedPath);
6486
7156
  } catch (e) {
6487
7157
  throw new import_graphql6.GraphQLError(
6488
7158
  `Error running onDelete hook for ${filepath}: ${e}`,
@@ -6517,20 +7187,26 @@ var Database = class {
6517
7187
  );
6518
7188
  const doc = await level2.keys({ limit: 1 }).next();
6519
7189
  if (!doc) {
6520
- await _indexContent(
6521
- this,
6522
- level2,
6523
- contentPaths,
7190
+ await _indexContent({
7191
+ database: this,
7192
+ level: level2,
7193
+ documentPaths: contentPaths,
6524
7194
  enqueueOps,
6525
7195
  collection,
6526
- userFields.map((field) => [
7196
+ passwordFields: userFields.map((field) => [
6527
7197
  ...field.path,
6528
7198
  field.passwordFieldName
6529
7199
  ])
6530
- );
7200
+ });
6531
7201
  }
6532
7202
  } else {
6533
- await _indexContent(this, level, contentPaths, enqueueOps, collection);
7203
+ await _indexContent({
7204
+ database: this,
7205
+ level,
7206
+ documentPaths: contentPaths,
7207
+ enqueueOps,
7208
+ collection
7209
+ });
6534
7210
  }
6535
7211
  }
6536
7212
  );
@@ -6566,7 +7242,7 @@ var Database = class {
6566
7242
  );
6567
7243
  }
6568
7244
  const metadata = await metadataLevel.get("metadata");
6569
- return metadata == null ? void 0 : metadata.version;
7245
+ return metadata?.version;
6570
7246
  }
6571
7247
  async initLevel() {
6572
7248
  if (this.contentLevel) {
@@ -6616,6 +7292,9 @@ var Database = class {
6616
7292
  info: templateInfo
6617
7293
  };
6618
7294
  }
7295
+ /**
7296
+ * Clears the internal cache of the tinaSchema and the lookup file. This allows the state to be reset
7297
+ */
6619
7298
  clearCache() {
6620
7299
  this.tinaSchema = null;
6621
7300
  this._lookup = null;
@@ -6640,7 +7319,7 @@ var hashPasswordVisitor = async (node, path7) => {
6640
7319
  const passwordValuePath = [...path7, "value"];
6641
7320
  const plaintextPassword = get(node, passwordValuePath);
6642
7321
  if (plaintextPassword) {
6643
- (0, import_lodash5.default)(
7322
+ (0, import_compat2.set)(
6644
7323
  node,
6645
7324
  passwordValuePath,
6646
7325
  await generatePasswordHash({ password: plaintextPassword })
@@ -6649,7 +7328,7 @@ var hashPasswordVisitor = async (node, path7) => {
6649
7328
  };
6650
7329
  var visitNodes = async (node, path7, callback) => {
6651
7330
  const [currentLevel, ...remainingLevels] = path7;
6652
- if (!(remainingLevels == null ? void 0 : remainingLevels.length)) {
7331
+ if (!remainingLevels?.length) {
6653
7332
  return callback(node, path7);
6654
7333
  }
6655
7334
  if (Array.isArray(node[currentLevel])) {
@@ -6665,18 +7344,27 @@ var hashPasswordValues = async (data, passwordFields) => Promise.all(
6665
7344
  async (passwordField) => visitNodes(data, passwordField, hashPasswordVisitor)
6666
7345
  )
6667
7346
  );
6668
- var isGitKeep = (filepath, collection) => filepath.endsWith(`.gitkeep.${(collection == null ? void 0 : collection.format) || "md"}`);
6669
- var _indexContent = async (database, level, documentPaths, enqueueOps, collection, passwordFields) => {
7347
+ var isGitKeep = (filepath, collection) => filepath.endsWith(`.gitkeep.${collection?.format || "md"}`);
7348
+ var _indexContent = async ({
7349
+ database,
7350
+ level,
7351
+ documentPaths,
7352
+ enqueueOps,
7353
+ collection,
7354
+ passwordFields,
7355
+ isPartialReindex
7356
+ }) => {
6670
7357
  let collectionIndexDefinitions;
6671
7358
  let collectionPath;
6672
7359
  if (collection) {
6673
7360
  const indexDefinitions = await database.getIndexDefinitions(level);
6674
- collectionIndexDefinitions = indexDefinitions == null ? void 0 : indexDefinitions[collection.name];
7361
+ collectionIndexDefinitions = indexDefinitions?.[collection.name];
6675
7362
  if (!collectionIndexDefinitions) {
6676
7363
  throw new Error(`No indexDefinitions for collection ${collection.name}`);
6677
7364
  }
6678
7365
  collectionPath = collection.path;
6679
7366
  }
7367
+ const collectionReferences = (await database.getCollectionReferences())?.[collection?.name];
6680
7368
  const tinaSchema = await database.getSchema();
6681
7369
  let templateInfo = null;
6682
7370
  if (collection) {
@@ -6694,27 +7382,77 @@ var _indexContent = async (database, level, documentPaths, enqueueOps, collectio
6694
7382
  if (!aliasedData) {
6695
7383
  return;
6696
7384
  }
6697
- if (passwordFields == null ? void 0 : passwordFields.length) {
7385
+ if (passwordFields?.length) {
6698
7386
  await hashPasswordValues(aliasedData, passwordFields);
6699
7387
  }
6700
- const normalizedPath = (0, import_schema_tools3.normalizePath)(filepath);
7388
+ const normalizedPath = (0, import_schema_tools4.normalizePath)(filepath);
7389
+ const rootSublevel = level.sublevel(
7390
+ CONTENT_ROOT_PREFIX,
7391
+ SUBLEVEL_OPTIONS
7392
+ );
6701
7393
  const folderKey = folderTreeBuilder.update(
6702
7394
  normalizedPath,
6703
7395
  collectionPath || ""
6704
7396
  );
7397
+ if (isPartialReindex) {
7398
+ const item = await rootSublevel.get(normalizedPath);
7399
+ if (item) {
7400
+ await database.contentLevel.batch([
7401
+ ...makeRefOpsForDocument(
7402
+ normalizedPath,
7403
+ collection?.name,
7404
+ collectionReferences,
7405
+ item,
7406
+ "del",
7407
+ level
7408
+ ),
7409
+ ...makeIndexOpsForDocument(
7410
+ normalizedPath,
7411
+ collection.name,
7412
+ collectionIndexDefinitions,
7413
+ item,
7414
+ "del",
7415
+ level
7416
+ ),
7417
+ // folder indices
7418
+ ...makeIndexOpsForDocument(
7419
+ normalizedPath,
7420
+ `${collection.name}_${folderKey}`,
7421
+ collectionIndexDefinitions,
7422
+ item,
7423
+ "del",
7424
+ level
7425
+ ),
7426
+ {
7427
+ type: "del",
7428
+ key: normalizedPath,
7429
+ sublevel: rootSublevel
7430
+ }
7431
+ ]);
7432
+ }
7433
+ }
6705
7434
  if (!isGitKeep(filepath, collection)) {
6706
7435
  await enqueueOps([
7436
+ ...makeRefOpsForDocument(
7437
+ normalizedPath,
7438
+ collection?.name,
7439
+ collectionReferences,
7440
+ aliasedData,
7441
+ "put",
7442
+ level
7443
+ ),
6707
7444
  ...makeIndexOpsForDocument(
6708
7445
  normalizedPath,
6709
- collection == null ? void 0 : collection.name,
7446
+ collection?.name,
6710
7447
  collectionIndexDefinitions,
6711
7448
  aliasedData,
6712
7449
  "put",
6713
7450
  level
6714
7451
  ),
7452
+ // folder indexes
6715
7453
  ...makeIndexOpsForDocument(
6716
7454
  normalizedPath,
6717
- `${collection == null ? void 0 : collection.name}_${folderKey}`,
7455
+ `${collection?.name}_${folderKey}`,
6718
7456
  collectionIndexDefinitions,
6719
7457
  aliasedData,
6720
7458
  "put",
@@ -6735,8 +7473,7 @@ var _indexContent = async (database, level, documentPaths, enqueueOps, collectio
6735
7473
  throw new TinaFetchError(`Unable to seed ${filepath}`, {
6736
7474
  originalError: error,
6737
7475
  file: filepath,
6738
- collection: collection == null ? void 0 : collection.name,
6739
- stack: error.stack
7476
+ collection: collection?.name
6740
7477
  });
6741
7478
  }
6742
7479
  });
@@ -6761,11 +7498,12 @@ var _deleteIndexContent = async (database, documentPaths, enqueueOps, collection
6761
7498
  const indexDefinitions = await database.getIndexDefinitions(
6762
7499
  database.contentLevel
6763
7500
  );
6764
- collectionIndexDefinitions = indexDefinitions == null ? void 0 : indexDefinitions[collection.name];
7501
+ collectionIndexDefinitions = indexDefinitions?.[collection.name];
6765
7502
  if (!collectionIndexDefinitions) {
6766
7503
  throw new Error(`No indexDefinitions for collection ${collection.name}`);
6767
7504
  }
6768
7505
  }
7506
+ const collectionReferences = (await database.getCollectionReferences())?.[collection?.name];
6769
7507
  const tinaSchema = await database.getSchema();
6770
7508
  let templateInfo = null;
6771
7509
  if (collection) {
@@ -6777,18 +7515,26 @@ var _deleteIndexContent = async (database, documentPaths, enqueueOps, collection
6777
7515
  );
6778
7516
  const folderTreeBuilder = new FolderTreeBuilder();
6779
7517
  await sequential(documentPaths, async (filepath) => {
6780
- const itemKey = (0, import_schema_tools3.normalizePath)(filepath);
7518
+ const itemKey = (0, import_schema_tools4.normalizePath)(filepath);
6781
7519
  const item = await rootLevel.get(itemKey);
6782
7520
  if (item) {
6783
7521
  const folderKey = folderTreeBuilder.update(
6784
7522
  itemKey,
6785
- (collection == null ? void 0 : collection.path) || ""
7523
+ collection?.path || ""
6786
7524
  );
6787
7525
  const aliasedData = templateInfo ? replaceNameOverrides(
6788
7526
  getTemplateForFile(templateInfo, item),
6789
7527
  item
6790
7528
  ) : item;
6791
7529
  await enqueueOps([
7530
+ ...makeRefOpsForDocument(
7531
+ itemKey,
7532
+ collection?.name,
7533
+ collectionReferences,
7534
+ aliasedData,
7535
+ "del",
7536
+ database.contentLevel
7537
+ ),
6792
7538
  ...makeIndexOpsForDocument(
6793
7539
  itemKey,
6794
7540
  collection.name,
@@ -6797,9 +7543,10 @@ var _deleteIndexContent = async (database, documentPaths, enqueueOps, collection
6797
7543
  "del",
6798
7544
  database.contentLevel
6799
7545
  ),
7546
+ // folder indexes
6800
7547
  ...makeIndexOpsForDocument(
6801
7548
  itemKey,
6802
- `${collection == null ? void 0 : collection.name}_${folderKey}`,
7549
+ `${collection?.name}_${folderKey}`,
6803
7550
  collectionIndexDefinitions,
6804
7551
  aliasedData,
6805
7552
  "del",
@@ -6863,14 +7610,14 @@ var getChangedFiles = async ({
6863
7610
  const rootDir = await findGitRoot(dir);
6864
7611
  let pathPrefix = "";
6865
7612
  if (rootDir !== dir) {
6866
- pathPrefix = (0, import_schema_tools3.normalizePath)(dir.substring(rootDir.length + 1));
7613
+ pathPrefix = (0, import_schema_tools4.normalizePath)(dir.substring(rootDir.length + 1));
6867
7614
  }
6868
7615
  await import_isomorphic_git.default.walk({
6869
7616
  fs: fs4,
6870
7617
  dir: rootDir,
6871
7618
  trees: [import_isomorphic_git.default.TREE({ ref: from }), import_isomorphic_git.default.TREE({ ref: to })],
6872
7619
  map: async function(filename, [A, B]) {
6873
- const relativePath = (0, import_schema_tools3.normalizePath)(filename).substring(pathPrefix.length);
7620
+ const relativePath = (0, import_schema_tools4.normalizePath)(filename).substring(pathPrefix.length);
6874
7621
  let matches = false;
6875
7622
  for (const [key, matcher] of Object.entries(pathFilter)) {
6876
7623
  if (relativePath.startsWith(key)) {
@@ -6884,12 +7631,12 @@ var getChangedFiles = async ({
6884
7631
  }
6885
7632
  }
6886
7633
  }
6887
- if (await (B == null ? void 0 : B.type()) === "tree") {
7634
+ if (await B?.type() === "tree") {
6888
7635
  return;
6889
7636
  }
6890
7637
  if (matches) {
6891
- const oidA = await (A == null ? void 0 : A.oid());
6892
- const oidB = await (B == null ? void 0 : B.oid());
7638
+ const oidA = await A?.oid();
7639
+ const oidB = await B?.oid();
6893
7640
  if (oidA !== oidB) {
6894
7641
  if (oidA === void 0) {
6895
7642
  results.added.push(relativePath);
@@ -6917,8 +7664,8 @@ var import_path5 = __toESM(require("path"));
6917
7664
  var import_normalize_path = __toESM(require("normalize-path"));
6918
7665
  var FilesystemBridge = class {
6919
7666
  constructor(rootPath, outputPath) {
6920
- this.rootPath = rootPath || "";
6921
- this.outputPath = outputPath || rootPath;
7667
+ this.rootPath = import_path5.default.resolve(rootPath);
7668
+ this.outputPath = outputPath ? import_path5.default.resolve(outputPath) : this.rootPath;
6922
7669
  }
6923
7670
  async glob(pattern, extension) {
6924
7671
  const basePath = import_path5.default.join(this.outputPath, ...pattern.split("/"));
@@ -6930,19 +7677,19 @@ var FilesystemBridge = class {
6930
7677
  }
6931
7678
  );
6932
7679
  const posixRootPath = (0, import_normalize_path.default)(this.outputPath);
6933
- return items.map((item) => {
6934
- return item.replace(posixRootPath, "").replace(/^\/|\/$/g, "");
6935
- });
7680
+ return items.map(
7681
+ (item) => item.substring(posixRootPath.length).replace(/^\/|\/$/g, "")
7682
+ );
6936
7683
  }
6937
7684
  async delete(filepath) {
6938
7685
  await import_fs_extra2.default.remove(import_path5.default.join(this.outputPath, filepath));
6939
7686
  }
6940
7687
  async get(filepath) {
6941
- return import_fs_extra2.default.readFileSync(import_path5.default.join(this.outputPath, filepath)).toString();
7688
+ return (await import_fs_extra2.default.readFile(import_path5.default.join(this.outputPath, filepath))).toString();
6942
7689
  }
6943
7690
  async put(filepath, data, basePathOverride) {
6944
7691
  const basePath = basePathOverride || this.outputPath;
6945
- await import_fs_extra2.default.outputFileSync(import_path5.default.join(basePath, filepath), data);
7692
+ await import_fs_extra2.default.outputFile(import_path5.default.join(basePath, filepath), data);
6946
7693
  }
6947
7694
  };
6948
7695
  var AuditFileSystemBridge = class extends FilesystemBridge {
@@ -7012,17 +7759,26 @@ var IsomorphicBridge = class {
7012
7759
  getAuthor() {
7013
7760
  return {
7014
7761
  ...this.author,
7015
- timestamp: Math.round(new Date().getTime() / 1e3),
7762
+ timestamp: Math.round((/* @__PURE__ */ new Date()).getTime() / 1e3),
7016
7763
  timezoneOffset: 0
7017
7764
  };
7018
7765
  }
7019
7766
  getCommitter() {
7020
7767
  return {
7021
7768
  ...this.committer,
7022
- timestamp: Math.round(new Date().getTime() / 1e3),
7769
+ timestamp: Math.round((/* @__PURE__ */ new Date()).getTime() / 1e3),
7023
7770
  timezoneOffset: 0
7024
7771
  };
7025
7772
  }
7773
+ /**
7774
+ * Recursively populate paths matching `pattern` for the given `entry`
7775
+ *
7776
+ * @param pattern - pattern to filter paths by
7777
+ * @param entry - TreeEntry to start building list from
7778
+ * @param path - base path
7779
+ * @param results
7780
+ * @private
7781
+ */
7026
7782
  async listEntries({
7027
7783
  pattern,
7028
7784
  entry,
@@ -7055,6 +7811,15 @@ var IsomorphicBridge = class {
7055
7811
  });
7056
7812
  }
7057
7813
  }
7814
+ /**
7815
+ * For the specified path, returns an object with an array containing the parts of the path (pathParts)
7816
+ * and an array containing the WalkerEntry objects for the path parts (pathEntries). Any null elements in the
7817
+ * pathEntries are placeholders for non-existent entries.
7818
+ *
7819
+ * @param path - path being resolved
7820
+ * @param ref - ref to resolve path entries for
7821
+ * @private
7822
+ */
7058
7823
  async resolvePathEntries(path7, ref) {
7059
7824
  let pathParts = path7.split("/");
7060
7825
  const result = await import_isomorphic_git2.default.walk({
@@ -7085,6 +7850,17 @@ var IsomorphicBridge = class {
7085
7850
  }
7086
7851
  return { pathParts, pathEntries };
7087
7852
  }
7853
+ /**
7854
+ * Updates tree entry and associated parent tree entries
7855
+ *
7856
+ * @param existingOid - the existing OID
7857
+ * @param updatedOid - the updated OID
7858
+ * @param path - the path of the entry being updated
7859
+ * @param type - the type of the entry being updated (blob or tree)
7860
+ * @param pathEntries - parent path entries
7861
+ * @param pathParts - parent path parts
7862
+ * @private
7863
+ */
7088
7864
  async updateTreeHierarchy(existingOid, updatedOid, path7, type, pathEntries, pathParts) {
7089
7865
  const lastIdx = pathEntries.length - 1;
7090
7866
  const parentEntry = pathEntries[lastIdx];
@@ -7140,6 +7916,13 @@ var IsomorphicBridge = class {
7140
7916
  );
7141
7917
  }
7142
7918
  }
7919
+ /**
7920
+ * Creates a commit for the specified tree and updates the specified ref to point to the commit
7921
+ *
7922
+ * @param treeSha - sha of the new tree
7923
+ * @param ref - the ref that should be updated
7924
+ * @private
7925
+ */
7143
7926
  async commitTree(treeSha, ref) {
7144
7927
  const commitSha = await import_isomorphic_git2.default.writeCommit({
7145
7928
  ...this.isomorphicConfig,
@@ -7152,6 +7935,7 @@ var IsomorphicBridge = class {
7152
7935
  })
7153
7936
  ],
7154
7937
  message: this.commitMessage,
7938
+ // TODO these should be configurable
7155
7939
  author: this.getAuthor(),
7156
7940
  committer: this.getCommitter()
7157
7941
  }
@@ -7390,5 +8174,5 @@ var buildSchema = async (config, flags) => {
7390
8174
  transformDocument,
7391
8175
  transformDocumentIntoPayload
7392
8176
  });
7393
- //! Replaces _.flattenDeep()
7394
8177
  //! Replaces _.get()
8178
+ //! Replaces _.flattenDeep()