@tinacms/graphql 0.0.0-ef282d9-20241024212433 → 0.0.0-f2577b9-20251119082459

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