@tinacms/graphql 0.0.0-bc59a81-20241030011355 → 0.0.0-bdc07c1-20250506013835

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,
@@ -1471,6 +1473,19 @@ var Builder = class {
1471
1473
  this.addToLookupMap = (lookup) => {
1472
1474
  this.lookupMap[lookup.type] = lookup;
1473
1475
  };
1476
+ /**
1477
+ * ```graphql
1478
+ * # ex.
1479
+ * {
1480
+ * getCollection(collection: $collection) {
1481
+ * name
1482
+ * documents {...}
1483
+ * }
1484
+ * }
1485
+ * ```
1486
+ *
1487
+ * @param collections
1488
+ */
1474
1489
  this.buildCollectionDefinition = async (collections) => {
1475
1490
  const name = "collection";
1476
1491
  const typeName = "Collection";
@@ -1541,6 +1556,19 @@ var Builder = class {
1541
1556
  required: true
1542
1557
  });
1543
1558
  };
1559
+ /**
1560
+ * ```graphql
1561
+ * # ex.
1562
+ * {
1563
+ * getCollections {
1564
+ * name
1565
+ * documents {...}
1566
+ * }
1567
+ * }
1568
+ * ```
1569
+ *
1570
+ * @param collections
1571
+ */
1544
1572
  this.buildMultiCollectionDefinition = async (collections) => {
1545
1573
  const name = "collections";
1546
1574
  const typeName = "Collection";
@@ -1551,6 +1579,17 @@ var Builder = class {
1551
1579
  required: true
1552
1580
  });
1553
1581
  };
1582
+ /**
1583
+ * ```graphql
1584
+ * # ex.
1585
+ * {
1586
+ * node(id: $id) {
1587
+ * id
1588
+ * data {...}
1589
+ * }
1590
+ * }
1591
+ * ```
1592
+ */
1554
1593
  this.multiNodeDocument = async () => {
1555
1594
  const name = "node";
1556
1595
  const args = [
@@ -1571,6 +1610,19 @@ var Builder = class {
1571
1610
  required: true
1572
1611
  });
1573
1612
  };
1613
+ /**
1614
+ * ```graphql
1615
+ * # ex.
1616
+ * {
1617
+ * getDocument(collection: $collection, relativePath: $relativePath) {
1618
+ * id
1619
+ * data {...}
1620
+ * }
1621
+ * }
1622
+ * ```
1623
+ *
1624
+ * @param collections
1625
+ */
1574
1626
  this.multiCollectionDocument = async (collections) => {
1575
1627
  const name = "document";
1576
1628
  const args = [
@@ -1596,6 +1648,19 @@ var Builder = class {
1596
1648
  required: true
1597
1649
  });
1598
1650
  };
1651
+ /**
1652
+ * ```graphql
1653
+ * # ex.
1654
+ * {
1655
+ * addPendingDocument(collection: $collection, relativePath: $relativePath, params: $params) {
1656
+ * id
1657
+ * data {...}
1658
+ * }
1659
+ * }
1660
+ * ```
1661
+ *
1662
+ * @param collections
1663
+ */
1599
1664
  this.addMultiCollectionDocumentMutation = async () => {
1600
1665
  return astBuilder.FieldDefinition({
1601
1666
  name: "addPendingDocument",
@@ -1620,6 +1685,19 @@ var Builder = class {
1620
1685
  type: astBuilder.TYPES.MultiCollectionDocument
1621
1686
  });
1622
1687
  };
1688
+ /**
1689
+ * ```graphql
1690
+ * # ex.
1691
+ * {
1692
+ * createDocument(relativePath: $relativePath, params: $params) {
1693
+ * id
1694
+ * data {...}
1695
+ * }
1696
+ * }
1697
+ * ```
1698
+ *
1699
+ * @param collections
1700
+ */
1623
1701
  this.buildCreateCollectionDocumentMutation = async (collections) => {
1624
1702
  return astBuilder.FieldDefinition({
1625
1703
  name: "createDocument",
@@ -1647,6 +1725,19 @@ var Builder = class {
1647
1725
  type: astBuilder.TYPES.MultiCollectionDocument
1648
1726
  });
1649
1727
  };
1728
+ /**
1729
+ * ```graphql
1730
+ * # ex.
1731
+ * {
1732
+ * updateDocument(relativePath: $relativePath, params: $params) {
1733
+ * id
1734
+ * data {...}
1735
+ * }
1736
+ * }
1737
+ * ```
1738
+ *
1739
+ * @param collections
1740
+ */
1650
1741
  this.buildUpdateCollectionDocumentMutation = async (collections) => {
1651
1742
  return astBuilder.FieldDefinition({
1652
1743
  name: "updateDocument",
@@ -1674,6 +1765,19 @@ var Builder = class {
1674
1765
  type: astBuilder.TYPES.MultiCollectionDocument
1675
1766
  });
1676
1767
  };
1768
+ /**
1769
+ * ```graphql
1770
+ * # ex.
1771
+ * {
1772
+ * deleteDocument(relativePath: $relativePath, params: $params) {
1773
+ * id
1774
+ * data {...}
1775
+ * }
1776
+ * }
1777
+ * ```
1778
+ *
1779
+ * @param collections
1780
+ */
1677
1781
  this.buildDeleteCollectionDocumentMutation = async (collections) => {
1678
1782
  return astBuilder.FieldDefinition({
1679
1783
  name: "deleteDocument",
@@ -1693,6 +1797,19 @@ var Builder = class {
1693
1797
  type: astBuilder.TYPES.MultiCollectionDocument
1694
1798
  });
1695
1799
  };
1800
+ /**
1801
+ * ```graphql
1802
+ * # ex.
1803
+ * {
1804
+ * createFolder(folderName: $folderName, params: $params) {
1805
+ * id
1806
+ * data {...}
1807
+ * }
1808
+ * }
1809
+ * ```
1810
+ *
1811
+ * @param collections
1812
+ */
1696
1813
  this.buildCreateCollectionFolderMutation = async () => {
1697
1814
  return astBuilder.FieldDefinition({
1698
1815
  name: "createFolder",
@@ -1712,6 +1829,19 @@ var Builder = class {
1712
1829
  type: astBuilder.TYPES.MultiCollectionDocument
1713
1830
  });
1714
1831
  };
1832
+ /**
1833
+ * ```graphql
1834
+ * # ex.
1835
+ * {
1836
+ * getPostDocument(relativePath: $relativePath) {
1837
+ * id
1838
+ * data {...}
1839
+ * }
1840
+ * }
1841
+ * ```
1842
+ *
1843
+ * @param collection
1844
+ */
1715
1845
  this.collectionDocument = async (collection) => {
1716
1846
  const name = NAMER.queryName([collection.name]);
1717
1847
  const type = await this._buildCollectionDocumentType(collection);
@@ -1772,6 +1902,20 @@ var Builder = class {
1772
1902
  const args = [];
1773
1903
  return astBuilder.FieldDefinition({ type, name, args, required: false });
1774
1904
  };
1905
+ /**
1906
+ * Turns a collection into a fragment that gets updated on build. This fragment does not resolve references
1907
+ * ```graphql
1908
+ * # ex.
1909
+ * fragment AuthorsParts on Authors {
1910
+ * name
1911
+ * avatar
1912
+ * ...
1913
+ * }
1914
+ * ```
1915
+ *
1916
+ * @public
1917
+ * @param collection a TinaCloud collection
1918
+ */
1775
1919
  this.collectionFragment = async (collection) => {
1776
1920
  const name = NAMER.dataTypeName(collection.namespace);
1777
1921
  const fragmentName = NAMER.fragmentName(collection.namespace);
@@ -1785,6 +1929,20 @@ var Builder = class {
1785
1929
  selections: filterSelections(selections)
1786
1930
  });
1787
1931
  };
1932
+ /**
1933
+ * Given a collection this function returns its selections set. For example for Post this would return
1934
+ *
1935
+ * "
1936
+ * body
1937
+ * title
1938
+ * ... on Author {
1939
+ * name
1940
+ * heroImg
1941
+ * }
1942
+ *
1943
+ * But in the AST format
1944
+ *
1945
+ * */
1788
1946
  this._getCollectionFragmentSelections = async (collection, depth) => {
1789
1947
  var _a;
1790
1948
  const selections = [];
@@ -1868,9 +2026,9 @@ var Builder = class {
1868
2026
  ]
1869
2027
  });
1870
2028
  }
2029
+ // TODO: Should we throw here?
1871
2030
  case "reference":
1872
- if (depth >= this.maxDepth)
1873
- return false;
2031
+ if (depth >= this.maxDepth) return false;
1874
2032
  if (!("collections" in field)) {
1875
2033
  return false;
1876
2034
  }
@@ -1902,6 +2060,7 @@ var Builder = class {
1902
2060
  name: field.name,
1903
2061
  selections: [
1904
2062
  ...selections,
2063
+ // This is ... on Document { id }
1905
2064
  {
1906
2065
  kind: "InlineFragment",
1907
2066
  typeCondition: {
@@ -1932,6 +2091,19 @@ var Builder = class {
1932
2091
  });
1933
2092
  }
1934
2093
  };
2094
+ /**
2095
+ * ```graphql
2096
+ * # ex.
2097
+ * mutation {
2098
+ * updatePostDocument(relativePath: $relativePath, params: $params) {
2099
+ * id
2100
+ * data {...}
2101
+ * }
2102
+ * }
2103
+ * ```
2104
+ *
2105
+ * @param collection
2106
+ */
1935
2107
  this.updateCollectionDocumentMutation = async (collection) => {
1936
2108
  return astBuilder.FieldDefinition({
1937
2109
  type: await this._buildCollectionDocumentType(collection),
@@ -1951,6 +2123,19 @@ var Builder = class {
1951
2123
  ]
1952
2124
  });
1953
2125
  };
2126
+ /**
2127
+ * ```graphql
2128
+ * # ex.
2129
+ * mutation {
2130
+ * createPostDocument(relativePath: $relativePath, params: $params) {
2131
+ * id
2132
+ * data {...}
2133
+ * }
2134
+ * }
2135
+ * ```
2136
+ *
2137
+ * @param collection
2138
+ */
1954
2139
  this.createCollectionDocumentMutation = async (collection) => {
1955
2140
  return astBuilder.FieldDefinition({
1956
2141
  type: await this._buildCollectionDocumentType(collection),
@@ -1970,6 +2155,22 @@ var Builder = class {
1970
2155
  ]
1971
2156
  });
1972
2157
  };
2158
+ /**
2159
+ * ```graphql
2160
+ * # ex.
2161
+ * {
2162
+ * getPostList(first: 10) {
2163
+ * edges {
2164
+ * node {
2165
+ * id
2166
+ * }
2167
+ * }
2168
+ * }
2169
+ * }
2170
+ * ```
2171
+ *
2172
+ * @param collection
2173
+ */
1973
2174
  this.collectionDocumentList = async (collection) => {
1974
2175
  const connectionName = NAMER.referenceConnectionType(collection.namespace);
1975
2176
  this.addToLookupMap({
@@ -1985,6 +2186,10 @@ var Builder = class {
1985
2186
  collection
1986
2187
  });
1987
2188
  };
2189
+ /**
2190
+ * GraphQL type definitions which remain unchanged regardless
2191
+ * of the supplied Tina schema. Ex. "node" interface
2192
+ */
1988
2193
  this.buildStaticDefinitions = () => staticDefinitions;
1989
2194
  this._buildCollectionDocumentType = async (collection, suffix = "", extraFields = [], extraInterfaces = []) => {
1990
2195
  const documentTypeName = NAMER.documentTypeName(collection.namespace);
@@ -2489,6 +2694,7 @@ var Builder = class {
2489
2694
  name: NAMER.dataFilterTypeName(namespace),
2490
2695
  fields: await sequential(collections, async (collection2) => {
2491
2696
  return astBuilder.InputValueDefinition({
2697
+ // @ts-ignore
2492
2698
  name: collection2.name,
2493
2699
  type: NAMER.dataFilterTypeName(collection2.namespace)
2494
2700
  });
@@ -2678,7 +2884,8 @@ Visit https://tina.io/docs/errors/ui-not-supported/ for more information
2678
2884
  });
2679
2885
  };
2680
2886
  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;
2887
+ this.maxDepth = // @ts-ignore
2888
+ (_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;
2682
2889
  this.tinaSchema = config.tinaSchema;
2683
2890
  this.lookupMap = {};
2684
2891
  }
@@ -2689,8 +2896,7 @@ Visit https://tina.io/docs/errors/ui-not-supported/ for more information
2689
2896
  selections.push(field);
2690
2897
  });
2691
2898
  const filteredSelections = filterSelections(selections);
2692
- if (!filteredSelections.length)
2693
- return false;
2899
+ if (!filteredSelections.length) return false;
2694
2900
  return astBuilder.InlineFragmentDefinition({
2695
2901
  selections: filteredSelections,
2696
2902
  name: NAMER.dataTypeName(template.namespace)
@@ -2724,12 +2930,13 @@ var filterSelections = (arr) => {
2724
2930
  };
2725
2931
 
2726
2932
  // src/schema/createSchema.ts
2727
- var import_schema_tools2 = require("@tinacms/schema-tools");
2933
+ var import_schema_tools3 = require("@tinacms/schema-tools");
2728
2934
 
2729
2935
  // src/schema/validate.ts
2936
+ var import_schema_tools = require("@tinacms/schema-tools");
2730
2937
  var import_lodash2 = __toESM(require("lodash.clonedeep"));
2731
2938
  var yup2 = __toESM(require("yup"));
2732
- var import_schema_tools = require("@tinacms/schema-tools");
2939
+ var import_schema_tools2 = require("@tinacms/schema-tools");
2733
2940
  var FIELD_TYPES = [
2734
2941
  "string",
2735
2942
  "number",
@@ -2742,7 +2949,7 @@ var FIELD_TYPES = [
2742
2949
  "password"
2743
2950
  ];
2744
2951
  var validateSchema = async (schema) => {
2745
- const schema2 = addNamespaceToSchema(
2952
+ const schema2 = (0, import_schema_tools.addNamespaceToSchema)(
2746
2953
  (0, import_lodash2.default)(schema)
2747
2954
  );
2748
2955
  const collections = await sequential(
@@ -2751,7 +2958,7 @@ var validateSchema = async (schema) => {
2751
2958
  );
2752
2959
  validationCollectionsPathAndMatch(collections);
2753
2960
  if (schema2.config) {
2754
- const config = (0, import_schema_tools.validateTinaCloudSchemaConfig)(schema2.config);
2961
+ const config = (0, import_schema_tools2.validateTinaCloudSchemaConfig)(schema2.config);
2755
2962
  return {
2756
2963
  collections,
2757
2964
  config
@@ -2771,6 +2978,7 @@ var validationCollectionsPathAndMatch = (collections) => {
2771
2978
  }).map((x) => `${x.path}${x.format || "md"}`);
2772
2979
  if (noMatchCollections.length !== new Set(noMatchCollections).size) {
2773
2980
  throw new Error(
2981
+ // TODO: add a link to the docs
2774
2982
  "Two collections without match can not have the same `path`. Please make the `path` unique or add a matches property to the collection."
2775
2983
  );
2776
2984
  }
@@ -2882,7 +3090,7 @@ var validateField = async (field) => {
2882
3090
  // package.json
2883
3091
  var package_default = {
2884
3092
  name: "@tinacms/graphql",
2885
- version: "1.5.6",
3093
+ version: "1.5.16",
2886
3094
  main: "dist/index.js",
2887
3095
  module: "dist/index.mjs",
2888
3096
  typings: "dist/index.d.ts",
@@ -2909,8 +3117,8 @@ var package_default = {
2909
3117
  build: "tinacms-scripts build",
2910
3118
  docs: "pnpm typedoc",
2911
3119
  serve: "pnpm nodemon dist/server.js",
2912
- test: "jest",
2913
- "test-watch": "jest --watch"
3120
+ test: "vitest run",
3121
+ "test-watch": "vitest"
2914
3122
  },
2915
3123
  dependencies: {
2916
3124
  "@iarna/toml": "^2.2.5",
@@ -2918,25 +3126,28 @@ var package_default = {
2918
3126
  "@tinacms/schema-tools": "workspace:*",
2919
3127
  "abstract-level": "^1.0.4",
2920
3128
  "date-fns": "^2.30.0",
2921
- "fast-glob": "^3.3.2",
2922
- "fs-extra": "^11.2.0",
3129
+ "fast-glob": "^3.3.3",
3130
+ "fs-extra": "^11.3.0",
2923
3131
  "glob-parent": "^6.0.2",
2924
3132
  graphql: "15.8.0",
2925
3133
  "gray-matter": "^4.0.3",
2926
- "isomorphic-git": "^1.27.1",
3134
+ "isomorphic-git": "^1.29.0",
2927
3135
  "js-sha1": "^0.6.0",
2928
3136
  "js-yaml": "^3.14.1",
2929
- "jsonpath-plus": "^6.0.1",
3137
+ "jsonpath-plus": "10.1.0",
2930
3138
  "lodash.clonedeep": "^4.5.0",
2931
3139
  "lodash.set": "^4.3.2",
2932
3140
  "lodash.uniqby": "^4.7.0",
2933
3141
  "many-level": "^2.0.0",
2934
3142
  micromatch: "4.0.8",
2935
3143
  "normalize-path": "^3.0.0",
2936
- "readable-stream": "^4.5.2",
3144
+ "readable-stream": "^4.7.0",
2937
3145
  scmp: "^2.1.0",
2938
3146
  yup: "^0.32.11"
2939
3147
  },
3148
+ peerDependencies: {
3149
+ "@tinacms/common": "workspace:*"
3150
+ },
2940
3151
  publishConfig: {
2941
3152
  registry: "https://registry.npmjs.org"
2942
3153
  },
@@ -2951,24 +3162,23 @@ var package_default = {
2951
3162
  "@types/estree": "^0.0.50",
2952
3163
  "@types/express": "^4.17.21",
2953
3164
  "@types/fs-extra": "^9.0.13",
2954
- "@types/jest": "^26.0.24",
2955
3165
  "@types/js-yaml": "^3.12.10",
2956
3166
  "@types/lodash.camelcase": "^4.3.9",
2957
3167
  "@types/lodash.upperfirst": "^4.3.9",
2958
3168
  "@types/lru-cache": "^5.1.1",
2959
3169
  "@types/mdast": "^3.0.15",
2960
3170
  "@types/micromatch": "^4.0.9",
2961
- "@types/node": "^22.7.4",
3171
+ "@types/node": "^22.13.1",
2962
3172
  "@types/normalize-path": "^3.0.2",
2963
3173
  "@types/ws": "^7.4.7",
2964
3174
  "@types/yup": "^0.29.14",
2965
- jest: "^29.7.0",
2966
- "jest-diff": "^29.7.0",
2967
3175
  "jest-file-snapshot": "^0.5.0",
2968
- "jest-matcher-utils": "^29.7.0",
2969
3176
  "memory-level": "^1.0.0",
2970
3177
  nodemon: "3.1.4",
2971
- typescript: "^5.6.2"
3178
+ typescript: "^5.7.3",
3179
+ vite: "^4.5.9",
3180
+ vitest: "^0.32.4",
3181
+ zod: "^3.24.2"
2972
3182
  }
2973
3183
  };
2974
3184
 
@@ -2983,7 +3193,7 @@ var createSchema = async ({
2983
3193
  if (flags && flags.length > 0) {
2984
3194
  meta["flags"] = flags;
2985
3195
  }
2986
- return new import_schema_tools2.TinaSchema({
3196
+ return new import_schema_tools3.TinaSchema({
2987
3197
  version: {
2988
3198
  fullVersion: package_default.version,
2989
3199
  major,
@@ -3039,6 +3249,7 @@ var _buildFragments = async (builder, tinaSchema) => {
3039
3249
  const fragDoc = {
3040
3250
  kind: "Document",
3041
3251
  definitions: (0, import_lodash3.default)(
3252
+ // @ts-ignore
3042
3253
  extractInlineTypes(fragmentDefinitionsFields),
3043
3254
  (node) => node.name.value
3044
3255
  )
@@ -3062,6 +3273,7 @@ var _buildQueries = async (builder, tinaSchema) => {
3062
3273
  fragName,
3063
3274
  queryName: queryListName,
3064
3275
  filterType: queryFilterTypeName,
3276
+ // look for flag to see if the data layer is enabled
3065
3277
  dataLayer: Boolean(
3066
3278
  (_c = (_b = (_a = tinaSchema.config) == null ? void 0 : _a.meta) == null ? void 0 : _b.flags) == null ? void 0 : _c.find((x) => x === "experimentalData")
3067
3279
  )
@@ -3071,6 +3283,7 @@ var _buildQueries = async (builder, tinaSchema) => {
3071
3283
  const queryDoc = {
3072
3284
  kind: "Document",
3073
3285
  definitions: (0, import_lodash3.default)(
3286
+ // @ts-ignore
3074
3287
  extractInlineTypes(operationsDefinitions),
3075
3288
  (node) => node.name.value
3076
3289
  )
@@ -3122,7 +3335,9 @@ var _buildSchema = async (builder, tinaSchema) => {
3122
3335
  await builder.buildCreateCollectionFolderMutation()
3123
3336
  );
3124
3337
  await sequential(collections, async (collection) => {
3125
- queryTypeDefinitionFields.push(await builder.collectionDocument(collection));
3338
+ queryTypeDefinitionFields.push(
3339
+ await builder.collectionDocument(collection)
3340
+ );
3126
3341
  if (collection.isAuthCollection) {
3127
3342
  queryTypeDefinitionFields.push(
3128
3343
  await builder.authenticationCollectionDocument(collection)
@@ -3159,6 +3374,7 @@ var _buildSchema = async (builder, tinaSchema) => {
3159
3374
  return {
3160
3375
  kind: "Document",
3161
3376
  definitions: (0, import_lodash3.default)(
3377
+ // @ts-ignore
3162
3378
  extractInlineTypes(definitions),
3163
3379
  (node) => node.name.value
3164
3380
  )
@@ -3175,6 +3391,9 @@ var import_isValid = __toESM(require("date-fns/isValid/index.js"));
3175
3391
  // src/mdx/index.ts
3176
3392
  var import_mdx = require("@tinacms/mdx");
3177
3393
 
3394
+ // src/resolver/index.ts
3395
+ var import_jsonpath_plus2 = require("jsonpath-plus");
3396
+
3178
3397
  // src/resolver/error.ts
3179
3398
  var TinaGraphQLError = class extends Error {
3180
3399
  constructor(message, extensions) {
@@ -3360,8 +3579,7 @@ var resolveMediaCloudToRelative = (value, config = { useRelativeMedia: true }, s
3360
3579
  }
3361
3580
  if (Array.isArray(value)) {
3362
3581
  return value.map((v) => {
3363
- if (!v || typeof v !== "string")
3364
- return v;
3582
+ if (!v || typeof v !== "string") return v;
3365
3583
  const cleanMediaRoot = cleanUpSlashes(
3366
3584
  schema.config.media.tina.mediaRoot
3367
3585
  );
@@ -3389,8 +3607,7 @@ var resolveMediaRelativeToCloud = (value, config = { useRelativeMedia: true }, s
3389
3607
  }
3390
3608
  if (Array.isArray(value)) {
3391
3609
  return value.map((v) => {
3392
- if (!v || typeof v !== "string")
3393
- return v;
3610
+ if (!v || typeof v !== "string") return v;
3394
3611
  const strippedValue = v.replace(cleanMediaRoot, "");
3395
3612
  return `https://${config.assetsHost}/${config.clientId}${strippedValue}`;
3396
3613
  });
@@ -3409,8 +3626,7 @@ var cleanUpSlashes = (path7) => {
3409
3626
  };
3410
3627
  var hasTinaMediaConfig = (schema) => {
3411
3628
  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;
3629
+ if (!((_b = (_a = schema.config) == null ? void 0 : _a.media) == null ? void 0 : _b.tina)) return false;
3414
3630
  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
3631
  return false;
3416
3632
  return true;
@@ -3437,7 +3653,9 @@ var LevelProxyHandler = {
3437
3653
  throw new Error(`The property, ${property.toString()}, doesn't exist`);
3438
3654
  }
3439
3655
  if (typeof target[property] !== "function") {
3440
- throw new Error(`The property, ${property.toString()}, is not a function`);
3656
+ throw new Error(
3657
+ `The property, ${property.toString()}, is not a function`
3658
+ );
3441
3659
  }
3442
3660
  if (property === "get") {
3443
3661
  return async (...args) => {
@@ -3454,6 +3672,7 @@ var LevelProxyHandler = {
3454
3672
  } else if (property === "sublevel") {
3455
3673
  return (...args) => {
3456
3674
  return new Proxy(
3675
+ // eslint-disable-next-line prefer-spread
3457
3676
  target[property].apply(target, args),
3458
3677
  LevelProxyHandler
3459
3678
  );
@@ -3476,7 +3695,7 @@ var import_path2 = __toESM(require("path"));
3476
3695
  var import_toml = __toESM(require("@iarna/toml"));
3477
3696
  var import_js_yaml = __toESM(require("js-yaml"));
3478
3697
  var import_gray_matter = __toESM(require("gray-matter"));
3479
- var import_schema_tools3 = require("@tinacms/schema-tools");
3698
+ var import_schema_tools4 = require("@tinacms/schema-tools");
3480
3699
  var import_micromatch = __toESM(require("micromatch"));
3481
3700
  var import_path = __toESM(require("path"));
3482
3701
 
@@ -3689,7 +3908,7 @@ var scanAllContent = async (tinaSchema, bridge, callback) => {
3689
3908
  const filesSeen = /* @__PURE__ */ new Map();
3690
3909
  const duplicateFiles = /* @__PURE__ */ new Set();
3691
3910
  await sequential(tinaSchema.getCollections(), async (collection) => {
3692
- const normalPath = (0, import_schema_tools3.normalizePath)(collection.path);
3911
+ const normalPath = (0, import_schema_tools4.normalizePath)(collection.path);
3693
3912
  const format = collection.format || "md";
3694
3913
  const documentPaths = await bridge.glob(normalPath, format);
3695
3914
  const matches = tinaSchema.getMatches({ collection });
@@ -3801,7 +4020,7 @@ var getTemplateForFile = (templateInfo, data) => {
3801
4020
  throw new Error(`Unable to determine template`);
3802
4021
  };
3803
4022
  var loadAndParseWithAliases = async (bridge, filepath, collection, templateInfo) => {
3804
- const dataString = await bridge.get((0, import_schema_tools3.normalizePath)(filepath));
4023
+ const dataString = await bridge.get((0, import_schema_tools4.normalizePath)(filepath));
3805
4024
  const data = parseFile(
3806
4025
  dataString,
3807
4026
  import_path.default.extname(filepath),
@@ -3823,6 +4042,9 @@ var loadAndParseWithAliases = async (bridge, filepath, collection, templateInfo)
3823
4042
 
3824
4043
  // src/database/datalayer.ts
3825
4044
  var DEFAULT_COLLECTION_SORT_KEY = "__filepath__";
4045
+ var REFS_COLLECTIONS_SORT_KEY = "__refs__";
4046
+ var REFS_REFERENCE_FIELD = "__tina_ref__";
4047
+ var REFS_PATH_FIELD = "__tina_ref_path__";
3826
4048
  var DEFAULT_NUMERIC_LPAD = 4;
3827
4049
  var applyPadding = (input, pad) => {
3828
4050
  if (pad) {
@@ -4280,7 +4502,7 @@ var FolderTreeBuilder = class {
4280
4502
  return this._tree;
4281
4503
  }
4282
4504
  update(documentPath, collectionPath) {
4283
- let folderPath = import_path2.default.dirname((0, import_schema_tools3.normalizePath)(documentPath));
4505
+ let folderPath = import_path2.default.dirname((0, import_schema_tools4.normalizePath)(documentPath));
4284
4506
  if (folderPath === ".") {
4285
4507
  folderPath = "";
4286
4508
  }
@@ -4293,7 +4515,7 @@ var FolderTreeBuilder = class {
4293
4515
  if (!this._tree[current2]) {
4294
4516
  this._tree[current2] = /* @__PURE__ */ new Set();
4295
4517
  }
4296
- this._tree[current2].add((0, import_schema_tools3.normalizePath)(import_path2.default.join(current2, part)));
4518
+ this._tree[current2].add((0, import_schema_tools4.normalizePath)(import_path2.default.join(current2, part)));
4297
4519
  parent.push(part);
4298
4520
  });
4299
4521
  const current = parent.join("/");
@@ -4332,6 +4554,7 @@ var makeFolderOpsForCollection = (folderTree, collection, indexDefinitions, opTy
4332
4554
  result.push({
4333
4555
  type: opType,
4334
4556
  key: `${collection.path}/${subFolderKey}.${collection.format}`,
4557
+ // replace the root with the collection path
4335
4558
  sublevel: indexSublevel,
4336
4559
  value: {}
4337
4560
  });
@@ -4395,6 +4618,57 @@ var makeIndexOpsForDocument = (filepath, collection, indexDefinitions, data, opT
4395
4618
  }
4396
4619
  return result;
4397
4620
  };
4621
+ var makeRefOpsForDocument = (filepath, collection, references, data, opType, level) => {
4622
+ const result = [];
4623
+ if (collection) {
4624
+ for (const [c, referencePaths] of Object.entries(references || {})) {
4625
+ if (!referencePaths.length) {
4626
+ continue;
4627
+ }
4628
+ const collectionSublevel = level.sublevel(c, SUBLEVEL_OPTIONS);
4629
+ const refSublevel = collectionSublevel.sublevel(
4630
+ REFS_COLLECTIONS_SORT_KEY,
4631
+ SUBLEVEL_OPTIONS
4632
+ );
4633
+ const references2 = {};
4634
+ for (const path7 of referencePaths) {
4635
+ const ref = (0, import_jsonpath_plus.JSONPath)({ path: path7, json: data });
4636
+ if (!ref) {
4637
+ continue;
4638
+ }
4639
+ if (Array.isArray(ref)) {
4640
+ for (const r of ref) {
4641
+ if (!r) {
4642
+ continue;
4643
+ }
4644
+ if (references2[r]) {
4645
+ references2[r].push(path7);
4646
+ } else {
4647
+ references2[r] = [path7];
4648
+ }
4649
+ }
4650
+ } else {
4651
+ if (references2[ref]) {
4652
+ references2[ref].push(path7);
4653
+ } else {
4654
+ references2[ref] = [path7];
4655
+ }
4656
+ }
4657
+ }
4658
+ for (const ref of Object.keys(references2)) {
4659
+ for (const path7 of references2[ref]) {
4660
+ result.push({
4661
+ type: opType,
4662
+ key: `${ref}${INDEX_KEY_FIELD_SEPARATOR}${path7}${INDEX_KEY_FIELD_SEPARATOR}${filepath}`,
4663
+ sublevel: refSublevel,
4664
+ value: opType === "put" ? {} : void 0
4665
+ });
4666
+ }
4667
+ }
4668
+ }
4669
+ }
4670
+ return result;
4671
+ };
4398
4672
  var makeStringEscaper = (regex, replacement) => {
4399
4673
  return (input) => {
4400
4674
  if (Array.isArray(input)) {
@@ -4447,6 +4721,7 @@ var resolveFieldData = async ({ namespace, ...field }, rawData, accumulator, tin
4447
4721
  case "password":
4448
4722
  accumulator[field.name] = {
4449
4723
  value: void 0,
4724
+ // never resolve the password hash
4450
4725
  passwordChangeRequired: (_a = value["passwordChangeRequired"]) != null ? _a : false
4451
4726
  };
4452
4727
  break;
@@ -4541,7 +4816,7 @@ var resolveFieldData = async ({ namespace, ...field }, rawData, accumulator, tin
4541
4816
  }
4542
4817
  return accumulator;
4543
4818
  };
4544
- var transformDocumentIntoPayload = async (fullPath, rawData, tinaSchema, config, isAudit) => {
4819
+ var transformDocumentIntoPayload = async (fullPath, rawData, tinaSchema, config, isAudit, hasReferences) => {
4545
4820
  const collection = tinaSchema.getCollection(rawData._collection);
4546
4821
  try {
4547
4822
  const template = tinaSchema.getTemplateForData({
@@ -4595,6 +4870,7 @@ var transformDocumentIntoPayload = async (fullPath, rawData, tinaSchema, config,
4595
4870
  basename,
4596
4871
  filename,
4597
4872
  extension,
4873
+ hasReferences,
4598
4874
  path: fullPath,
4599
4875
  relativePath,
4600
4876
  breadcrumbs,
@@ -4614,6 +4890,34 @@ var transformDocumentIntoPayload = async (fullPath, rawData, tinaSchema, config,
4614
4890
  throw e;
4615
4891
  }
4616
4892
  };
4893
+ var updateObjectWithJsonPath = (obj, path7, oldValue, newValue) => {
4894
+ let updated = false;
4895
+ if (!path7.includes(".") && !path7.includes("[")) {
4896
+ if (path7 in obj && obj[path7] === oldValue) {
4897
+ obj[path7] = newValue;
4898
+ updated = true;
4899
+ }
4900
+ return { object: obj, updated };
4901
+ }
4902
+ const parentPath = path7.replace(/\.[^.\[\]]+$/, "");
4903
+ const keyToUpdate = path7.match(/[^.\[\]]+$/)[0];
4904
+ const parents = (0, import_jsonpath_plus2.JSONPath)({
4905
+ path: parentPath,
4906
+ json: obj,
4907
+ resultType: "value"
4908
+ });
4909
+ if (parents.length > 0) {
4910
+ parents.forEach((parent) => {
4911
+ if (parent && typeof parent === "object" && keyToUpdate in parent) {
4912
+ if (parent[keyToUpdate] === oldValue) {
4913
+ parent[keyToUpdate] = newValue;
4914
+ updated = true;
4915
+ }
4916
+ }
4917
+ });
4918
+ }
4919
+ return { object: obj, updated };
4920
+ };
4617
4921
  var Resolver = class {
4618
4922
  constructor(init) {
4619
4923
  this.init = init;
@@ -4621,6 +4925,7 @@ var Resolver = class {
4621
4925
  const collection = this.tinaSchema.getCollection(collectionName);
4622
4926
  const extraFields = {};
4623
4927
  return {
4928
+ // return the collection and hasDocuments to resolve documents at a lower level
4624
4929
  documents: { collection, hasDocuments },
4625
4930
  ...collection,
4626
4931
  ...extraFields
@@ -4628,7 +4933,9 @@ var Resolver = class {
4628
4933
  };
4629
4934
  this.getRaw = async (fullPath) => {
4630
4935
  if (typeof fullPath !== "string") {
4631
- throw new Error(`fullPath must be of type string for getDocument request`);
4936
+ throw new Error(
4937
+ `fullPath must be of type string for getDocument request`
4938
+ );
4632
4939
  }
4633
4940
  return this.database.get(fullPath);
4634
4941
  };
@@ -4655,22 +4962,28 @@ var Resolver = class {
4655
4962
  );
4656
4963
  }
4657
4964
  };
4658
- this.getDocument = async (fullPath) => {
4965
+ this.getDocument = async (fullPath, opts = {}) => {
4659
4966
  if (typeof fullPath !== "string") {
4660
- throw new Error(`fullPath must be of type string for getDocument request`);
4967
+ throw new Error(
4968
+ `fullPath must be of type string for getDocument request`
4969
+ );
4661
4970
  }
4662
4971
  const rawData = await this.getRaw(fullPath);
4972
+ const hasReferences = (opts == null ? void 0 : opts.checkReferences) ? await this.hasReferences(fullPath, opts.collection) : void 0;
4663
4973
  return transformDocumentIntoPayload(
4664
4974
  fullPath,
4665
4975
  rawData,
4666
4976
  this.tinaSchema,
4667
4977
  this.config,
4668
- this.isAudit
4978
+ this.isAudit,
4979
+ hasReferences
4669
4980
  );
4670
4981
  };
4671
4982
  this.deleteDocument = async (fullPath) => {
4672
4983
  if (typeof fullPath !== "string") {
4673
- throw new Error(`fullPath must be of type string for getDocument request`);
4984
+ throw new Error(
4985
+ `fullPath must be of type string for getDocument request`
4986
+ );
4674
4987
  }
4675
4988
  await this.database.delete(fullPath);
4676
4989
  };
@@ -4705,7 +5018,9 @@ var Resolver = class {
4705
5018
  );
4706
5019
  } else {
4707
5020
  return this.buildFieldMutations(
5021
+ // @ts-ignore FIXME Argument of type 'string | object' is not assignable to parameter of type '{ [fieldName: string]: string | object | (string | object)[]; }'
4708
5022
  fieldValue,
5023
+ //@ts-ignore
4709
5024
  objectTemplate,
4710
5025
  existingData
4711
5026
  );
@@ -4717,6 +5032,7 @@ var Resolver = class {
4717
5032
  fieldValue.map(async (item) => {
4718
5033
  if (typeof item === "string") {
4719
5034
  throw new Error(
5035
+ //@ts-ignore
4720
5036
  `Expected object for template value for field ${field.name}`
4721
5037
  );
4722
5038
  }
@@ -4725,16 +5041,19 @@ var Resolver = class {
4725
5041
  });
4726
5042
  const [templateName] = Object.entries(item)[0];
4727
5043
  const template = templates.find(
5044
+ //@ts-ignore
4728
5045
  (template2) => template2.name === templateName
4729
5046
  );
4730
5047
  if (!template) {
4731
5048
  throw new Error(`Expected to find template ${templateName}`);
4732
5049
  }
4733
5050
  return {
5051
+ // @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
5052
  ...await this.buildFieldMutations(
4735
5053
  item[template.name],
4736
5054
  template
4737
5055
  ),
5056
+ //@ts-ignore
4738
5057
  _template: template.name
4739
5058
  };
4740
5059
  })
@@ -4742,6 +5061,7 @@ var Resolver = class {
4742
5061
  } else {
4743
5062
  if (typeof fieldValue === "string") {
4744
5063
  throw new Error(
5064
+ //@ts-ignore
4745
5065
  `Expected object for template value for field ${field.name}`
4746
5066
  );
4747
5067
  }
@@ -4750,16 +5070,19 @@ var Resolver = class {
4750
5070
  });
4751
5071
  const [templateName] = Object.entries(fieldValue)[0];
4752
5072
  const template = templates.find(
5073
+ //@ts-ignore
4753
5074
  (template2) => template2.name === templateName
4754
5075
  );
4755
5076
  if (!template) {
4756
5077
  throw new Error(`Expected to find template ${templateName}`);
4757
5078
  }
4758
5079
  return {
5080
+ // @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
5081
  ...await this.buildFieldMutations(
4760
5082
  fieldValue[template.name],
4761
5083
  template
4762
5084
  ),
5085
+ //@ts-ignore
4763
5086
  _template: template.name
4764
5087
  };
4765
5088
  }
@@ -4799,6 +5122,7 @@ var Resolver = class {
4799
5122
  return this.getDocument(realPath);
4800
5123
  }
4801
5124
  const params = await this.buildObjectMutations(
5125
+ // @ts-ignore
4802
5126
  args.params[collection.name],
4803
5127
  collection
4804
5128
  );
@@ -4844,6 +5168,7 @@ var Resolver = class {
4844
5168
  const values = {
4845
5169
  ...oldDoc,
4846
5170
  ...await this.buildFieldMutations(
5171
+ // @ts-ignore FIXME: failing on unknown, which we don't need to know because it's recursive
4847
5172
  templateParams,
4848
5173
  template,
4849
5174
  doc == null ? void 0 : doc._rawData
@@ -4857,13 +5182,22 @@ var Resolver = class {
4857
5182
  return this.getDocument(realPath);
4858
5183
  }
4859
5184
  const params = await this.buildObjectMutations(
5185
+ //@ts-ignore
4860
5186
  isCollectionSpecific ? args.params : args.params[collection.name],
4861
5187
  collection,
4862
5188
  doc == null ? void 0 : doc._rawData
4863
5189
  );
4864
- await this.database.put(realPath, { ...oldDoc, ...params }, collection.name);
5190
+ await this.database.put(
5191
+ realPath,
5192
+ { ...oldDoc, ...params },
5193
+ collection.name
5194
+ );
4865
5195
  return this.getDocument(realPath);
4866
5196
  };
5197
+ /**
5198
+ * Returns top-level fields which are not defined in the collection, so their
5199
+ * values are not eliminated from Tina when new values are saved
5200
+ */
4867
5201
  this.resolveLegacyValues = (oldDoc, collection) => {
4868
5202
  const legacyValues = {};
4869
5203
  Object.entries(oldDoc).forEach(([key, value]) => {
@@ -4969,6 +5303,40 @@ var Resolver = class {
4969
5303
  if (isDeletion) {
4970
5304
  const doc = await this.getDocument(realPath);
4971
5305
  await this.deleteDocument(realPath);
5306
+ if (await this.hasReferences(realPath, collection)) {
5307
+ const collRefs = await this.findReferences(realPath, collection);
5308
+ for (const [collection2, docsWithRefs] of Object.entries(collRefs)) {
5309
+ for (const [pathToDocWithRef, referencePaths] of Object.entries(
5310
+ docsWithRefs
5311
+ )) {
5312
+ let refDoc = await this.getRaw(pathToDocWithRef);
5313
+ let hasUpdate = false;
5314
+ for (const path7 of referencePaths) {
5315
+ const { object: object2, updated } = updateObjectWithJsonPath(
5316
+ refDoc,
5317
+ path7,
5318
+ realPath,
5319
+ null
5320
+ );
5321
+ refDoc = object2;
5322
+ hasUpdate = updated || hasUpdate;
5323
+ }
5324
+ if (hasUpdate) {
5325
+ const collectionWithRef = this.tinaSchema.getCollectionByFullPath(pathToDocWithRef);
5326
+ if (!collectionWithRef) {
5327
+ throw new Error(
5328
+ `Unable to find collection for ${pathToDocWithRef}`
5329
+ );
5330
+ }
5331
+ await this.database.put(
5332
+ pathToDocWithRef,
5333
+ refDoc,
5334
+ collectionWithRef.name
5335
+ );
5336
+ }
5337
+ }
5338
+ }
5339
+ }
4972
5340
  return doc;
4973
5341
  }
4974
5342
  if (isUpdateName) {
@@ -4985,12 +5353,49 @@ var Resolver = class {
4985
5353
  collection == null ? void 0 : collection.path,
4986
5354
  args.params.relativePath
4987
5355
  );
5356
+ if (newRealPath === realPath) {
5357
+ return doc;
5358
+ }
4988
5359
  await this.database.put(newRealPath, doc._rawData, collection.name);
4989
5360
  await this.deleteDocument(realPath);
5361
+ const collRefs = await this.findReferences(realPath, collection);
5362
+ for (const [collection2, docsWithRefs] of Object.entries(collRefs)) {
5363
+ for (const [pathToDocWithRef, referencePaths] of Object.entries(
5364
+ docsWithRefs
5365
+ )) {
5366
+ let docWithRef = await this.getRaw(pathToDocWithRef);
5367
+ let hasUpdate = false;
5368
+ for (const path7 of referencePaths) {
5369
+ const { object: object2, updated } = updateObjectWithJsonPath(
5370
+ docWithRef,
5371
+ path7,
5372
+ realPath,
5373
+ newRealPath
5374
+ );
5375
+ docWithRef = object2;
5376
+ hasUpdate = updated || hasUpdate;
5377
+ }
5378
+ if (hasUpdate) {
5379
+ const collectionWithRef = this.tinaSchema.getCollectionByFullPath(pathToDocWithRef);
5380
+ if (!collectionWithRef) {
5381
+ throw new Error(
5382
+ `Unable to find collection for ${pathToDocWithRef}`
5383
+ );
5384
+ }
5385
+ await this.database.put(
5386
+ pathToDocWithRef,
5387
+ docWithRef,
5388
+ collectionWithRef.name
5389
+ );
5390
+ }
5391
+ }
5392
+ }
4990
5393
  return this.getDocument(newRealPath);
4991
5394
  }
4992
5395
  if (alreadyExists === false) {
4993
- throw new Error(`Unable to update document, ${realPath} does not exist`);
5396
+ throw new Error(
5397
+ `Unable to update document, ${realPath} does not exist`
5398
+ );
4994
5399
  }
4995
5400
  return this.updateResolveDocument({
4996
5401
  collection,
@@ -5000,7 +5405,10 @@ var Resolver = class {
5000
5405
  isCollectionSpecific
5001
5406
  });
5002
5407
  } else {
5003
- return this.getDocument(realPath);
5408
+ return this.getDocument(realPath, {
5409
+ collection,
5410
+ checkReferences: true
5411
+ });
5004
5412
  }
5005
5413
  };
5006
5414
  this.resolveCollectionConnections = async ({ ids }) => {
@@ -5037,6 +5445,7 @@ var Resolver = class {
5037
5445
  },
5038
5446
  collection: referencedCollection,
5039
5447
  hydrator: (path7) => path7
5448
+ // just return the path
5040
5449
  }
5041
5450
  );
5042
5451
  const { edges } = resolvedCollectionConnection;
@@ -5104,6 +5513,82 @@ var Resolver = class {
5104
5513
  }
5105
5514
  };
5106
5515
  };
5516
+ /**
5517
+ * Checks if a document has references to it
5518
+ * @param id The id of the document to check for references
5519
+ * @param c The collection to check for references
5520
+ * @returns true if the document has references, false otherwise
5521
+ */
5522
+ this.hasReferences = async (id, c) => {
5523
+ let count = 0;
5524
+ await this.database.query(
5525
+ {
5526
+ collection: c.name,
5527
+ filterChain: makeFilterChain({
5528
+ conditions: [
5529
+ {
5530
+ filterPath: REFS_REFERENCE_FIELD,
5531
+ filterExpression: {
5532
+ _type: "string",
5533
+ _list: false,
5534
+ eq: id
5535
+ }
5536
+ }
5537
+ ]
5538
+ }),
5539
+ sort: REFS_COLLECTIONS_SORT_KEY
5540
+ },
5541
+ (refId) => {
5542
+ count++;
5543
+ return refId;
5544
+ }
5545
+ );
5546
+ if (count) {
5547
+ return true;
5548
+ }
5549
+ return false;
5550
+ };
5551
+ /**
5552
+ * Finds references to a document
5553
+ * @param id the id of the document to find references to
5554
+ * @param c the collection to find references in
5555
+ * @returns a map of references to the document
5556
+ */
5557
+ this.findReferences = async (id, c) => {
5558
+ const references = {};
5559
+ await this.database.query(
5560
+ {
5561
+ collection: c.name,
5562
+ filterChain: makeFilterChain({
5563
+ conditions: [
5564
+ {
5565
+ filterPath: REFS_REFERENCE_FIELD,
5566
+ filterExpression: {
5567
+ _type: "string",
5568
+ _list: false,
5569
+ eq: id
5570
+ }
5571
+ }
5572
+ ]
5573
+ }),
5574
+ sort: REFS_COLLECTIONS_SORT_KEY
5575
+ },
5576
+ (refId, rawItem) => {
5577
+ if (!references[c.name]) {
5578
+ references[c.name] = {};
5579
+ }
5580
+ if (!references[c.name][refId]) {
5581
+ references[c.name][refId] = [];
5582
+ }
5583
+ const referencePath = rawItem == null ? void 0 : rawItem[REFS_PATH_FIELD];
5584
+ if (referencePath) {
5585
+ references[c.name][refId].push(referencePath);
5586
+ }
5587
+ return refId;
5588
+ }
5589
+ );
5590
+ return references;
5591
+ };
5107
5592
  this.buildFieldMutations = async (fieldParams, template, existingData) => {
5108
5593
  var _a;
5109
5594
  const accum = {};
@@ -5191,6 +5676,27 @@ var Resolver = class {
5191
5676
  }
5192
5677
  return accum;
5193
5678
  };
5679
+ /**
5680
+ * A mutation looks nearly identical between updateDocument:
5681
+ * ```graphql
5682
+ * updateDocument(collection: $collection,relativePath: $path, params: {
5683
+ * post: {
5684
+ * title: "Hello, World"
5685
+ * }
5686
+ * })`
5687
+ * ```
5688
+ * and `updatePostDocument`:
5689
+ * ```graphql
5690
+ * updatePostDocument(relativePath: $path, params: {
5691
+ * title: "Hello, World"
5692
+ * })
5693
+ * ```
5694
+ * The problem here is that we don't know whether the payload came from `updateDocument`
5695
+ * or `updatePostDocument` (we could, but for now it's easier not to pipe those details through),
5696
+ * But we do know that when given a `args.collection` value, we can assume that
5697
+ * this was a `updateDocument` request, and thus - should grab the data
5698
+ * from the corresponding field name in the key
5699
+ */
5194
5700
  this.buildParams = (args) => {
5195
5701
  try {
5196
5702
  assertShape(
@@ -5291,7 +5797,10 @@ var resolve = async ({
5291
5797
  const graphQLSchema = (0, import_graphql5.buildASTSchema)(graphQLSchemaAst);
5292
5798
  const tinaConfig = await database.getTinaSchema();
5293
5799
  const tinaSchema = await createSchema({
5800
+ // TODO: please update all the types to import from @tinacms/schema-tools
5801
+ // @ts-ignore
5294
5802
  schema: tinaConfig,
5803
+ // @ts-ignore
5295
5804
  flags: (_a = tinaConfig == null ? void 0 : tinaConfig.meta) == null ? void 0 : _a.flags
5296
5805
  });
5297
5806
  const resolver = createResolver({
@@ -5308,8 +5817,7 @@ var resolve = async ({
5308
5817
  database
5309
5818
  },
5310
5819
  typeResolver: async (source, _args, info) => {
5311
- if (source.__typename)
5312
- return source.__typename;
5820
+ if (source.__typename) return source.__typename;
5313
5821
  const namedType = (0, import_graphql5.getNamedType)(info.returnType).toString();
5314
5822
  const lookup = await database.getLookup(namedType);
5315
5823
  if (lookup.resolveType === "unionData") {
@@ -5461,11 +5969,13 @@ var resolve = async ({
5461
5969
  (0, import_lodash4.default)(
5462
5970
  params,
5463
5971
  userField.path.slice(1),
5972
+ // remove _rawData from users path
5464
5973
  users.map((u) => {
5465
5974
  if (user[idFieldName] === u[idFieldName]) {
5466
5975
  return user;
5467
5976
  }
5468
5977
  return {
5978
+ // don't overwrite other users' passwords
5469
5979
  ...u,
5470
5980
  [passwordFieldName]: {
5471
5981
  ...u[passwordFieldName],
@@ -5488,6 +5998,9 @@ var resolve = async ({
5488
5998
  }
5489
5999
  const isCreation = lookup[info.fieldName] === "create";
5490
6000
  switch (lookup.resolveType) {
6001
+ /**
6002
+ * `node(id: $id)`
6003
+ */
5491
6004
  case "nodeDocument":
5492
6005
  assertShape(
5493
6006
  args,
@@ -5519,6 +6032,7 @@ var resolve = async ({
5519
6032
  collection: args.collection,
5520
6033
  isMutation,
5521
6034
  isCreation,
6035
+ // Right now this is the only case for deletion
5522
6036
  isDeletion: info.fieldName === "deleteDocument",
5523
6037
  isFolderCreation: info.fieldName === "createFolder",
5524
6038
  isUpdateName: Boolean((_a2 = args == null ? void 0 : args.params) == null ? void 0 : _a2.relativePath),
@@ -5528,6 +6042,9 @@ var resolve = async ({
5528
6042
  return result;
5529
6043
  }
5530
6044
  return value;
6045
+ /**
6046
+ * eg `getMovieDocument.data.actors`
6047
+ */
5531
6048
  case "multiCollectionDocumentList":
5532
6049
  if (Array.isArray(value)) {
5533
6050
  return {
@@ -5539,7 +6056,15 @@ var resolve = async ({
5539
6056
  }
5540
6057
  if (info.fieldName === "documents" && (value == null ? void 0 : value.collection) && (value == null ? void 0 : value.hasDocuments)) {
5541
6058
  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") {
6059
+ if (
6060
+ // 1. Make sure that the filter exists
6061
+ typeof (args == null ? void 0 : args.filter) !== "undefined" && (args == null ? void 0 : args.filter) !== null && // 2. Make sure that the collection name exists
6062
+ // @ts-ignore
6063
+ typeof ((_b = value == null ? void 0 : value.collection) == null ? void 0 : _b.name) === "string" && // 3. Make sure that the collection name is in the filter and is not undefined
6064
+ // @ts-ignore
6065
+ Object.keys(args.filter).includes((_c = value == null ? void 0 : value.collection) == null ? void 0 : _c.name) && // @ts-ignore
6066
+ typeof args.filter[(_d = value == null ? void 0 : value.collection) == null ? void 0 : _d.name] !== "undefined"
6067
+ ) {
5543
6068
  filter = args.filter[value.collection.name];
5544
6069
  }
5545
6070
  return resolver.resolveCollectionConnection({
@@ -5547,12 +6072,20 @@ var resolve = async ({
5547
6072
  ...args,
5548
6073
  filter
5549
6074
  },
6075
+ // @ts-ignore
5550
6076
  collection: value.collection
5551
6077
  });
5552
6078
  }
5553
6079
  throw new Error(
5554
6080
  `Expected an array for result of ${info.fieldName} at ${info.path}`
5555
6081
  );
6082
+ /**
6083
+ * Collections-specific getter
6084
+ * eg. `getPostDocument`/`createPostDocument`/`updatePostDocument`
6085
+ *
6086
+ * if coming from a query result
6087
+ * the field will be `node`
6088
+ */
5556
6089
  case "collectionDocument": {
5557
6090
  if (value) {
5558
6091
  return value;
@@ -5567,11 +6100,32 @@ var resolve = async ({
5567
6100
  });
5568
6101
  return result;
5569
6102
  }
6103
+ /**
6104
+ * Collections-specific list getter
6105
+ * eg. `getPageList`
6106
+ */
5570
6107
  case "collectionDocumentList":
5571
6108
  return resolver.resolveCollectionConnection({
5572
6109
  args,
5573
6110
  collection: tinaSchema.getCollection(lookup.collection)
5574
6111
  });
6112
+ /**
6113
+ * A polymorphic data set, it can be from a document's data
6114
+ * of any nested object which can be one of many shapes
6115
+ *
6116
+ * ```graphql
6117
+ * getPostDocument(relativePath: $relativePath) {
6118
+ * data {...} <- this part
6119
+ * }
6120
+ * ```
6121
+ * ```graphql
6122
+ * getBlockDocument(relativePath: $relativePath) {
6123
+ * data {
6124
+ * blocks {...} <- or this part
6125
+ * }
6126
+ * }
6127
+ * ```
6128
+ */
5575
6129
  case "unionData":
5576
6130
  if (!value) {
5577
6131
  if (args.relativePath) {
@@ -5636,8 +6190,7 @@ var TinaLevelClient = class extends import_many_level.ManyLevelGuest {
5636
6190
  this.port = port || 9e3;
5637
6191
  }
5638
6192
  openConnection() {
5639
- if (this._connected)
5640
- return;
6193
+ if (this._connected) return;
5641
6194
  const socket = (0, import_net.connect)(this.port);
5642
6195
  (0, import_readable_stream.pipeline)(socket, this.createRpcStream(), socket, () => {
5643
6196
  this._connected = false;
@@ -5757,7 +6310,7 @@ var Database = class {
5757
6310
  const contentObject = await level.sublevel(
5758
6311
  CONTENT_ROOT_PREFIX,
5759
6312
  SUBLEVEL_OPTIONS
5760
- ).get((0, import_schema_tools3.normalizePath)(filepath));
6313
+ ).get((0, import_schema_tools4.normalizePath)(filepath));
5761
6314
  if (!contentObject) {
5762
6315
  throw new NotFoundError(`Unable to find record ${filepath}`);
5763
6316
  }
@@ -5769,6 +6322,7 @@ var Database = class {
5769
6322
  }
5770
6323
  };
5771
6324
  this.addPendingDocument = async (filepath, data) => {
6325
+ var _a;
5772
6326
  await this.initLevel();
5773
6327
  const dataFields = await this.formatBodyOnPayload(filepath, data);
5774
6328
  const collection = await this.collectionForPath(filepath);
@@ -5782,7 +6336,8 @@ var Database = class {
5782
6336
  );
5783
6337
  const indexDefinitions = await this.getIndexDefinitions(this.contentLevel);
5784
6338
  const collectionIndexDefinitions = indexDefinitions == null ? void 0 : indexDefinitions[collection.name];
5785
- const normalizedPath = (0, import_schema_tools3.normalizePath)(filepath);
6339
+ const collectionReferences = (_a = await this.getCollectionReferences()) == null ? void 0 : _a[collection.name];
6340
+ const normalizedPath = (0, import_schema_tools4.normalizePath)(filepath);
5786
6341
  if (!(collection == null ? void 0 : collection.isDetached)) {
5787
6342
  if (this.bridge) {
5788
6343
  await this.bridge.put(normalizedPath, stringifiedFile);
@@ -5810,6 +6365,14 @@ var Database = class {
5810
6365
  let delOps = [];
5811
6366
  if (!isGitKeep(normalizedPath, collection)) {
5812
6367
  putOps = [
6368
+ ...makeRefOpsForDocument(
6369
+ normalizedPath,
6370
+ collection == null ? void 0 : collection.name,
6371
+ collectionReferences,
6372
+ dataFields,
6373
+ "put",
6374
+ level
6375
+ ),
5813
6376
  ...makeIndexOpsForDocument(
5814
6377
  normalizedPath,
5815
6378
  collection == null ? void 0 : collection.name,
@@ -5818,6 +6381,7 @@ var Database = class {
5818
6381
  "put",
5819
6382
  level
5820
6383
  ),
6384
+ // folder indices
5821
6385
  ...makeIndexOpsForDocument(
5822
6386
  normalizedPath,
5823
6387
  `${collection == null ? void 0 : collection.name}_${folderKey}`,
@@ -5832,6 +6396,14 @@ var Database = class {
5832
6396
  SUBLEVEL_OPTIONS
5833
6397
  ).get(normalizedPath);
5834
6398
  delOps = existingItem ? [
6399
+ ...makeRefOpsForDocument(
6400
+ normalizedPath,
6401
+ collection == null ? void 0 : collection.name,
6402
+ collectionReferences,
6403
+ existingItem,
6404
+ "del",
6405
+ level
6406
+ ),
5835
6407
  ...makeIndexOpsForDocument(
5836
6408
  normalizedPath,
5837
6409
  collection == null ? void 0 : collection.name,
@@ -5840,6 +6412,7 @@ var Database = class {
5840
6412
  "del",
5841
6413
  level
5842
6414
  ),
6415
+ // folder indices
5843
6416
  ...makeIndexOpsForDocument(
5844
6417
  normalizedPath,
5845
6418
  `${collection == null ? void 0 : collection.name}_${folderKey}`,
@@ -5866,7 +6439,7 @@ var Database = class {
5866
6439
  await level.batch(ops);
5867
6440
  };
5868
6441
  this.put = async (filepath, data, collectionName) => {
5869
- var _a, _b;
6442
+ var _a, _b, _c;
5870
6443
  await this.initLevel();
5871
6444
  try {
5872
6445
  if (SYSTEM_FILES.includes(filepath)) {
@@ -5879,13 +6452,14 @@ var Database = class {
5879
6452
  );
5880
6453
  collectionIndexDefinitions = indexDefinitions == null ? void 0 : indexDefinitions[collectionName];
5881
6454
  }
5882
- const normalizedPath = (0, import_schema_tools3.normalizePath)(filepath);
6455
+ const collectionReferences = (_a = await this.getCollectionReferences()) == null ? void 0 : _a[collectionName];
6456
+ const normalizedPath = (0, import_schema_tools4.normalizePath)(filepath);
5883
6457
  const dataFields = await this.formatBodyOnPayload(filepath, data);
5884
6458
  const collection = await this.collectionForPath(filepath);
5885
6459
  if (!collection) {
5886
6460
  throw new import_graphql6.GraphQLError(`Unable to find collection for ${filepath}.`);
5887
6461
  }
5888
- if (((_a = collection.match) == null ? void 0 : _a.exclude) || ((_b = collection.match) == null ? void 0 : _b.include)) {
6462
+ if (((_b = collection.match) == null ? void 0 : _b.exclude) || ((_c = collection.match) == null ? void 0 : _c.include)) {
5889
6463
  const matches = this.tinaSchema.getMatches({ collection });
5890
6464
  const match = import_micromatch2.default.isMatch(filepath, matches);
5891
6465
  if (!match) {
@@ -5926,6 +6500,14 @@ var Database = class {
5926
6500
  let delOps = [];
5927
6501
  if (!isGitKeep(normalizedPath, collection)) {
5928
6502
  putOps = [
6503
+ ...makeRefOpsForDocument(
6504
+ normalizedPath,
6505
+ collectionName,
6506
+ collectionReferences,
6507
+ dataFields,
6508
+ "put",
6509
+ level
6510
+ ),
5929
6511
  ...makeIndexOpsForDocument(
5930
6512
  normalizedPath,
5931
6513
  collectionName,
@@ -5934,6 +6516,7 @@ var Database = class {
5934
6516
  "put",
5935
6517
  level
5936
6518
  ),
6519
+ // folder indices
5937
6520
  ...makeIndexOpsForDocument(
5938
6521
  normalizedPath,
5939
6522
  `${collection == null ? void 0 : collection.name}_${folderKey}`,
@@ -5948,6 +6531,14 @@ var Database = class {
5948
6531
  SUBLEVEL_OPTIONS
5949
6532
  ).get(normalizedPath);
5950
6533
  delOps = existingItem ? [
6534
+ ...makeRefOpsForDocument(
6535
+ normalizedPath,
6536
+ collectionName,
6537
+ collectionReferences,
6538
+ existingItem,
6539
+ "del",
6540
+ level
6541
+ ),
5951
6542
  ...makeIndexOpsForDocument(
5952
6543
  normalizedPath,
5953
6544
  collectionName,
@@ -5956,6 +6547,7 @@ var Database = class {
5956
6547
  "del",
5957
6548
  level
5958
6549
  ),
6550
+ // folder indices
5959
6551
  ...makeIndexOpsForDocument(
5960
6552
  normalizedPath,
5961
6553
  `${collection == null ? void 0 : collection.name}_${folderKey}`,
@@ -6033,6 +6625,7 @@ var Database = class {
6033
6625
  aliasedData,
6034
6626
  extension,
6035
6627
  writeTemplateKey,
6628
+ //templateInfo.type === 'union',
6036
6629
  {
6037
6630
  frontmatterFormat: collection == null ? void 0 : collection.frontmatterFormat,
6038
6631
  frontmatterDelimiters: collection == null ? void 0 : collection.frontmatterDelimiters
@@ -6050,7 +6643,7 @@ var Database = class {
6050
6643
  };
6051
6644
  this.getLookup = async (returnType) => {
6052
6645
  await this.initLevel();
6053
- const lookupPath = (0, import_schema_tools3.normalizePath)(
6646
+ const lookupPath = (0, import_schema_tools4.normalizePath)(
6054
6647
  import_node_path.default.join(this.getGeneratedFolder(), `_lookup.json`)
6055
6648
  );
6056
6649
  if (!this._lookup) {
@@ -6063,7 +6656,7 @@ var Database = class {
6063
6656
  };
6064
6657
  this.getGraphQLSchema = async () => {
6065
6658
  await this.initLevel();
6066
- const graphqlPath = (0, import_schema_tools3.normalizePath)(
6659
+ const graphqlPath = (0, import_schema_tools4.normalizePath)(
6067
6660
  import_node_path.default.join(this.getGeneratedFolder(), `_graphql.json`)
6068
6661
  );
6069
6662
  return await this.contentLevel.sublevel(
@@ -6071,11 +6664,12 @@ var Database = class {
6071
6664
  SUBLEVEL_OPTIONS
6072
6665
  ).get(graphqlPath);
6073
6666
  };
6667
+ //TODO - is there a reason why the database fetches some config with "bridge.get", and some with "store.get"?
6074
6668
  this.getGraphQLSchemaFromBridge = async () => {
6075
6669
  if (!this.bridge) {
6076
6670
  throw new Error(`No bridge configured`);
6077
6671
  }
6078
- const graphqlPath = (0, import_schema_tools3.normalizePath)(
6672
+ const graphqlPath = (0, import_schema_tools4.normalizePath)(
6079
6673
  import_node_path.default.join(this.getGeneratedFolder(), `_graphql.json`)
6080
6674
  );
6081
6675
  const _graphql = await this.bridge.get(graphqlPath);
@@ -6083,7 +6677,7 @@ var Database = class {
6083
6677
  };
6084
6678
  this.getTinaSchema = async (level) => {
6085
6679
  await this.initLevel();
6086
- const schemaPath = (0, import_schema_tools3.normalizePath)(
6680
+ const schemaPath = (0, import_schema_tools4.normalizePath)(
6087
6681
  import_node_path.default.join(this.getGeneratedFolder(), `_schema.json`)
6088
6682
  );
6089
6683
  return await (level || this.contentLevel).sublevel(
@@ -6099,7 +6693,7 @@ var Database = class {
6099
6693
  const schema = existingSchema || await this.getTinaSchema(level || this.contentLevel);
6100
6694
  if (!schema) {
6101
6695
  throw new Error(
6102
- `Unable to get schema from level db: ${(0, import_schema_tools3.normalizePath)(
6696
+ `Unable to get schema from level db: ${(0, import_schema_tools4.normalizePath)(
6103
6697
  import_node_path.default.join(this.getGeneratedFolder(), `_schema.json`)
6104
6698
  )}`
6105
6699
  );
@@ -6107,6 +6701,22 @@ var Database = class {
6107
6701
  this.tinaSchema = await createSchema({ schema });
6108
6702
  return this.tinaSchema;
6109
6703
  };
6704
+ this.getCollectionReferences = async (level) => {
6705
+ if (this.collectionReferences) {
6706
+ return this.collectionReferences;
6707
+ }
6708
+ const result = {};
6709
+ const schema = await this.getSchema(level || this.contentLevel);
6710
+ const collections = schema.getCollections();
6711
+ for (const collection of collections) {
6712
+ const collectionReferences = this.tinaSchema.findReferencesFromCollection(
6713
+ collection.name
6714
+ );
6715
+ result[collection.name] = collectionReferences;
6716
+ }
6717
+ this.collectionReferences = result;
6718
+ return result;
6719
+ };
6110
6720
  this.getIndexDefinitions = async (level) => {
6111
6721
  if (!this.collectionIndexDefinitions) {
6112
6722
  await new Promise(async (resolve2, reject) => {
@@ -6116,10 +6726,53 @@ var Database = class {
6116
6726
  const collections = schema.getCollections();
6117
6727
  for (const collection of collections) {
6118
6728
  const indexDefinitions = {
6119
- [DEFAULT_COLLECTION_SORT_KEY]: { fields: [] }
6729
+ [DEFAULT_COLLECTION_SORT_KEY]: { fields: [] },
6730
+ // provide a default sort key which is the file sort
6731
+ // pseudo-index for the collection's references
6732
+ [REFS_COLLECTIONS_SORT_KEY]: {
6733
+ fields: [
6734
+ {
6735
+ name: REFS_REFERENCE_FIELD,
6736
+ type: "string",
6737
+ list: false
6738
+ },
6739
+ {
6740
+ name: REFS_PATH_FIELD,
6741
+ type: "string",
6742
+ list: false
6743
+ }
6744
+ ]
6745
+ }
6120
6746
  };
6121
- if (collection.fields) {
6122
- for (const field of collection.fields) {
6747
+ let fields = [];
6748
+ if (collection.templates) {
6749
+ const templateFieldMap = {};
6750
+ const conflictedFields = /* @__PURE__ */ new Set();
6751
+ for (const template of collection.templates) {
6752
+ for (const field of template.fields) {
6753
+ if (!templateFieldMap[field.name]) {
6754
+ templateFieldMap[field.name] = field;
6755
+ } else {
6756
+ if (templateFieldMap[field.name].type !== field.type) {
6757
+ console.warn(
6758
+ `Field ${field.name} has conflicting types in templates - skipping index`
6759
+ );
6760
+ conflictedFields.add(field.name);
6761
+ }
6762
+ }
6763
+ }
6764
+ }
6765
+ for (const conflictedField in conflictedFields) {
6766
+ delete templateFieldMap[conflictedField];
6767
+ }
6768
+ for (const field of Object.values(templateFieldMap)) {
6769
+ fields.push(field);
6770
+ }
6771
+ } else if (collection.fields) {
6772
+ fields = collection.fields;
6773
+ }
6774
+ if (fields) {
6775
+ for (const field of fields) {
6123
6776
  if (field.indexed !== void 0 && field.indexed === false || field.type === "object") {
6124
6777
  continue;
6125
6778
  }
@@ -6268,29 +6921,36 @@ var Database = class {
6268
6921
  }
6269
6922
  startKey = startKey || key || "";
6270
6923
  endKey = key || "";
6271
- edges = [...edges, { cursor: key, path: filepath }];
6924
+ edges = [...edges, { cursor: key, path: filepath, value: itemRecord }];
6272
6925
  }
6273
6926
  return {
6274
- edges: await sequential(edges, async (edge) => {
6275
- try {
6276
- const node = await hydrator(edge.path);
6277
- return {
6278
- node,
6279
- cursor: btoa(edge.cursor)
6280
- };
6281
- } catch (error) {
6282
- console.log(error);
6283
- if (error instanceof Error && (!edge.path.includes(".tina/__generated__/_graphql.json") || !edge.path.includes("tina/__generated__/_graphql.json"))) {
6284
- throw new TinaQueryError({
6285
- originalError: error,
6286
- file: edge.path,
6287
- collection: collection.name,
6288
- stack: error.stack
6289
- });
6927
+ edges: await sequential(
6928
+ edges,
6929
+ async ({
6930
+ cursor,
6931
+ path: path7,
6932
+ value
6933
+ }) => {
6934
+ try {
6935
+ const node = await hydrator(path7, value);
6936
+ return {
6937
+ node,
6938
+ cursor: btoa(cursor)
6939
+ };
6940
+ } catch (error) {
6941
+ console.log(error);
6942
+ if (error instanceof Error && (!path7.includes(".tina/__generated__/_graphql.json") || !path7.includes("tina/__generated__/_graphql.json"))) {
6943
+ throw new TinaQueryError({
6944
+ originalError: error,
6945
+ file: path7,
6946
+ collection: collection.name,
6947
+ stack: error.stack
6948
+ });
6949
+ }
6950
+ throw error;
6290
6951
  }
6291
- throw error;
6292
6952
  }
6293
- }),
6953
+ ),
6294
6954
  pageInfo: {
6295
6955
  hasPreviousPage,
6296
6956
  hasNextPage,
@@ -6315,7 +6975,7 @@ var Database = class {
6315
6975
  try {
6316
6976
  lookup = lookupFromLockFile || JSON.parse(
6317
6977
  await this.bridge.get(
6318
- (0, import_schema_tools3.normalizePath)(
6978
+ (0, import_schema_tools4.normalizePath)(
6319
6979
  import_node_path.default.join(this.getGeneratedFolder(), "_lookup.json")
6320
6980
  )
6321
6981
  )
@@ -6340,15 +7000,15 @@ var Database = class {
6340
7000
  }
6341
7001
  const contentRootLevel = nextLevel.sublevel(CONTENT_ROOT_PREFIX, SUBLEVEL_OPTIONS);
6342
7002
  await contentRootLevel.put(
6343
- (0, import_schema_tools3.normalizePath)(import_node_path.default.join(this.getGeneratedFolder(), "_graphql.json")),
7003
+ (0, import_schema_tools4.normalizePath)(import_node_path.default.join(this.getGeneratedFolder(), "_graphql.json")),
6344
7004
  graphQLSchema
6345
7005
  );
6346
7006
  await contentRootLevel.put(
6347
- (0, import_schema_tools3.normalizePath)(import_node_path.default.join(this.getGeneratedFolder(), "_schema.json")),
7007
+ (0, import_schema_tools4.normalizePath)(import_node_path.default.join(this.getGeneratedFolder(), "_schema.json")),
6348
7008
  tinaSchema.schema
6349
7009
  );
6350
7010
  await contentRootLevel.put(
6351
- (0, import_schema_tools3.normalizePath)(import_node_path.default.join(this.getGeneratedFolder(), "_lookup.json")),
7011
+ (0, import_schema_tools4.normalizePath)(import_node_path.default.join(this.getGeneratedFolder(), "_lookup.json")),
6352
7012
  lookup
6353
7013
  );
6354
7014
  const result = await this._indexAllContent(
@@ -6414,13 +7074,14 @@ var Database = class {
6414
7074
  documentPaths,
6415
7075
  async (collection, documentPaths2) => {
6416
7076
  if (collection && !collection.isDetached) {
6417
- await _indexContent(
6418
- this,
6419
- this.contentLevel,
6420
- documentPaths2,
7077
+ await _indexContent({
7078
+ database: this,
7079
+ level: this.contentLevel,
7080
+ documentPaths: documentPaths2,
6421
7081
  enqueueOps,
6422
- collection
6423
- );
7082
+ collection,
7083
+ isPartialReindex: true
7084
+ });
6424
7085
  }
6425
7086
  }
6426
7087
  );
@@ -6430,23 +7091,25 @@ var Database = class {
6430
7091
  }
6431
7092
  };
6432
7093
  this.delete = async (filepath) => {
7094
+ var _a;
6433
7095
  await this.initLevel();
6434
7096
  const collection = await this.collectionForPath(filepath);
6435
7097
  if (!collection) {
6436
7098
  throw new Error(`No collection found for path: ${filepath}`);
6437
7099
  }
6438
7100
  const indexDefinitions = await this.getIndexDefinitions(this.contentLevel);
7101
+ const collectionReferences = (_a = await this.getCollectionReferences()) == null ? void 0 : _a[collection.name];
6439
7102
  const collectionIndexDefinitions = indexDefinitions == null ? void 0 : indexDefinitions[collection.name];
6440
7103
  let level = this.contentLevel;
6441
7104
  if (collection == null ? void 0 : collection.isDetached) {
6442
7105
  level = this.appLevel.sublevel(collection == null ? void 0 : 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
7152
  if (!(collection == null ? void 0 : 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
  );
@@ -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;
@@ -6666,7 +7347,16 @@ var hashPasswordValues = async (data, passwordFields) => Promise.all(
6666
7347
  )
6667
7348
  );
6668
7349
  var isGitKeep = (filepath, collection) => filepath.endsWith(`.gitkeep.${(collection == null ? void 0 : collection.format) || "md"}`);
6669
- var _indexContent = async (database, level, documentPaths, enqueueOps, collection, passwordFields) => {
7350
+ var _indexContent = async ({
7351
+ database,
7352
+ level,
7353
+ documentPaths,
7354
+ enqueueOps,
7355
+ collection,
7356
+ passwordFields,
7357
+ isPartialReindex
7358
+ }) => {
7359
+ var _a;
6670
7360
  let collectionIndexDefinitions;
6671
7361
  let collectionPath;
6672
7362
  if (collection) {
@@ -6677,6 +7367,7 @@ var _indexContent = async (database, level, documentPaths, enqueueOps, collectio
6677
7367
  }
6678
7368
  collectionPath = collection.path;
6679
7369
  }
7370
+ const collectionReferences = (_a = await database.getCollectionReferences()) == null ? void 0 : _a[collection == null ? void 0 : collection.name];
6680
7371
  const tinaSchema = await database.getSchema();
6681
7372
  let templateInfo = null;
6682
7373
  if (collection) {
@@ -6697,13 +7388,62 @@ var _indexContent = async (database, level, documentPaths, enqueueOps, collectio
6697
7388
  if (passwordFields == null ? void 0 : passwordFields.length) {
6698
7389
  await hashPasswordValues(aliasedData, passwordFields);
6699
7390
  }
6700
- const normalizedPath = (0, import_schema_tools3.normalizePath)(filepath);
7391
+ const normalizedPath = (0, import_schema_tools4.normalizePath)(filepath);
7392
+ const rootSublevel = level.sublevel(
7393
+ CONTENT_ROOT_PREFIX,
7394
+ SUBLEVEL_OPTIONS
7395
+ );
6701
7396
  const folderKey = folderTreeBuilder.update(
6702
7397
  normalizedPath,
6703
7398
  collectionPath || ""
6704
7399
  );
7400
+ if (isPartialReindex) {
7401
+ const item = await rootSublevel.get(normalizedPath);
7402
+ if (item) {
7403
+ await database.contentLevel.batch([
7404
+ ...makeRefOpsForDocument(
7405
+ normalizedPath,
7406
+ collection == null ? void 0 : collection.name,
7407
+ collectionReferences,
7408
+ item,
7409
+ "del",
7410
+ level
7411
+ ),
7412
+ ...makeIndexOpsForDocument(
7413
+ normalizedPath,
7414
+ collection.name,
7415
+ collectionIndexDefinitions,
7416
+ item,
7417
+ "del",
7418
+ level
7419
+ ),
7420
+ // folder indices
7421
+ ...makeIndexOpsForDocument(
7422
+ normalizedPath,
7423
+ `${collection.name}_${folderKey}`,
7424
+ collectionIndexDefinitions,
7425
+ item,
7426
+ "del",
7427
+ level
7428
+ ),
7429
+ {
7430
+ type: "del",
7431
+ key: normalizedPath,
7432
+ sublevel: rootSublevel
7433
+ }
7434
+ ]);
7435
+ }
7436
+ }
6705
7437
  if (!isGitKeep(filepath, collection)) {
6706
7438
  await enqueueOps([
7439
+ ...makeRefOpsForDocument(
7440
+ normalizedPath,
7441
+ collection == null ? void 0 : collection.name,
7442
+ collectionReferences,
7443
+ aliasedData,
7444
+ "put",
7445
+ level
7446
+ ),
6707
7447
  ...makeIndexOpsForDocument(
6708
7448
  normalizedPath,
6709
7449
  collection == null ? void 0 : collection.name,
@@ -6712,6 +7452,7 @@ var _indexContent = async (database, level, documentPaths, enqueueOps, collectio
6712
7452
  "put",
6713
7453
  level
6714
7454
  ),
7455
+ // folder indexes
6715
7456
  ...makeIndexOpsForDocument(
6716
7457
  normalizedPath,
6717
7458
  `${collection == null ? void 0 : collection.name}_${folderKey}`,
@@ -6753,6 +7494,7 @@ var _indexContent = async (database, level, documentPaths, enqueueOps, collectio
6753
7494
  }
6754
7495
  };
6755
7496
  var _deleteIndexContent = async (database, documentPaths, enqueueOps, collection) => {
7497
+ var _a;
6756
7498
  if (!documentPaths.length) {
6757
7499
  return;
6758
7500
  }
@@ -6766,6 +7508,7 @@ var _deleteIndexContent = async (database, documentPaths, enqueueOps, collection
6766
7508
  throw new Error(`No indexDefinitions for collection ${collection.name}`);
6767
7509
  }
6768
7510
  }
7511
+ const collectionReferences = (_a = await database.getCollectionReferences()) == null ? void 0 : _a[collection == null ? void 0 : collection.name];
6769
7512
  const tinaSchema = await database.getSchema();
6770
7513
  let templateInfo = null;
6771
7514
  if (collection) {
@@ -6777,7 +7520,7 @@ var _deleteIndexContent = async (database, documentPaths, enqueueOps, collection
6777
7520
  );
6778
7521
  const folderTreeBuilder = new FolderTreeBuilder();
6779
7522
  await sequential(documentPaths, async (filepath) => {
6780
- const itemKey = (0, import_schema_tools3.normalizePath)(filepath);
7523
+ const itemKey = (0, import_schema_tools4.normalizePath)(filepath);
6781
7524
  const item = await rootLevel.get(itemKey);
6782
7525
  if (item) {
6783
7526
  const folderKey = folderTreeBuilder.update(
@@ -6789,6 +7532,14 @@ var _deleteIndexContent = async (database, documentPaths, enqueueOps, collection
6789
7532
  item
6790
7533
  ) : item;
6791
7534
  await enqueueOps([
7535
+ ...makeRefOpsForDocument(
7536
+ itemKey,
7537
+ collection == null ? void 0 : collection.name,
7538
+ collectionReferences,
7539
+ aliasedData,
7540
+ "del",
7541
+ database.contentLevel
7542
+ ),
6792
7543
  ...makeIndexOpsForDocument(
6793
7544
  itemKey,
6794
7545
  collection.name,
@@ -6797,6 +7548,7 @@ var _deleteIndexContent = async (database, documentPaths, enqueueOps, collection
6797
7548
  "del",
6798
7549
  database.contentLevel
6799
7550
  ),
7551
+ // folder indexes
6800
7552
  ...makeIndexOpsForDocument(
6801
7553
  itemKey,
6802
7554
  `${collection == null ? void 0 : collection.name}_${folderKey}`,
@@ -6863,14 +7615,14 @@ var getChangedFiles = async ({
6863
7615
  const rootDir = await findGitRoot(dir);
6864
7616
  let pathPrefix = "";
6865
7617
  if (rootDir !== dir) {
6866
- pathPrefix = (0, import_schema_tools3.normalizePath)(dir.substring(rootDir.length + 1));
7618
+ pathPrefix = (0, import_schema_tools4.normalizePath)(dir.substring(rootDir.length + 1));
6867
7619
  }
6868
7620
  await import_isomorphic_git.default.walk({
6869
7621
  fs: fs4,
6870
7622
  dir: rootDir,
6871
7623
  trees: [import_isomorphic_git.default.TREE({ ref: from }), import_isomorphic_git.default.TREE({ ref: to })],
6872
7624
  map: async function(filename, [A, B]) {
6873
- const relativePath = (0, import_schema_tools3.normalizePath)(filename).substring(pathPrefix.length);
7625
+ const relativePath = (0, import_schema_tools4.normalizePath)(filename).substring(pathPrefix.length);
6874
7626
  let matches = false;
6875
7627
  for (const [key, matcher] of Object.entries(pathFilter)) {
6876
7628
  if (relativePath.startsWith(key)) {
@@ -7012,17 +7764,26 @@ var IsomorphicBridge = class {
7012
7764
  getAuthor() {
7013
7765
  return {
7014
7766
  ...this.author,
7015
- timestamp: Math.round(new Date().getTime() / 1e3),
7767
+ timestamp: Math.round((/* @__PURE__ */ new Date()).getTime() / 1e3),
7016
7768
  timezoneOffset: 0
7017
7769
  };
7018
7770
  }
7019
7771
  getCommitter() {
7020
7772
  return {
7021
7773
  ...this.committer,
7022
- timestamp: Math.round(new Date().getTime() / 1e3),
7774
+ timestamp: Math.round((/* @__PURE__ */ new Date()).getTime() / 1e3),
7023
7775
  timezoneOffset: 0
7024
7776
  };
7025
7777
  }
7778
+ /**
7779
+ * Recursively populate paths matching `pattern` for the given `entry`
7780
+ *
7781
+ * @param pattern - pattern to filter paths by
7782
+ * @param entry - TreeEntry to start building list from
7783
+ * @param path - base path
7784
+ * @param results
7785
+ * @private
7786
+ */
7026
7787
  async listEntries({
7027
7788
  pattern,
7028
7789
  entry,
@@ -7055,6 +7816,15 @@ var IsomorphicBridge = class {
7055
7816
  });
7056
7817
  }
7057
7818
  }
7819
+ /**
7820
+ * For the specified path, returns an object with an array containing the parts of the path (pathParts)
7821
+ * and an array containing the WalkerEntry objects for the path parts (pathEntries). Any null elements in the
7822
+ * pathEntries are placeholders for non-existent entries.
7823
+ *
7824
+ * @param path - path being resolved
7825
+ * @param ref - ref to resolve path entries for
7826
+ * @private
7827
+ */
7058
7828
  async resolvePathEntries(path7, ref) {
7059
7829
  let pathParts = path7.split("/");
7060
7830
  const result = await import_isomorphic_git2.default.walk({
@@ -7085,6 +7855,17 @@ var IsomorphicBridge = class {
7085
7855
  }
7086
7856
  return { pathParts, pathEntries };
7087
7857
  }
7858
+ /**
7859
+ * Updates tree entry and associated parent tree entries
7860
+ *
7861
+ * @param existingOid - the existing OID
7862
+ * @param updatedOid - the updated OID
7863
+ * @param path - the path of the entry being updated
7864
+ * @param type - the type of the entry being updated (blob or tree)
7865
+ * @param pathEntries - parent path entries
7866
+ * @param pathParts - parent path parts
7867
+ * @private
7868
+ */
7088
7869
  async updateTreeHierarchy(existingOid, updatedOid, path7, type, pathEntries, pathParts) {
7089
7870
  const lastIdx = pathEntries.length - 1;
7090
7871
  const parentEntry = pathEntries[lastIdx];
@@ -7140,6 +7921,13 @@ var IsomorphicBridge = class {
7140
7921
  );
7141
7922
  }
7142
7923
  }
7924
+ /**
7925
+ * Creates a commit for the specified tree and updates the specified ref to point to the commit
7926
+ *
7927
+ * @param treeSha - sha of the new tree
7928
+ * @param ref - the ref that should be updated
7929
+ * @private
7930
+ */
7143
7931
  async commitTree(treeSha, ref) {
7144
7932
  const commitSha = await import_isomorphic_git2.default.writeCommit({
7145
7933
  ...this.isomorphicConfig,
@@ -7152,6 +7940,7 @@ var IsomorphicBridge = class {
7152
7940
  })
7153
7941
  ],
7154
7942
  message: this.commitMessage,
7943
+ // TODO these should be configurable
7155
7944
  author: this.getAuthor(),
7156
7945
  committer: this.getCommitter()
7157
7946
  }
@@ -7390,5 +8179,5 @@ var buildSchema = async (config, flags) => {
7390
8179
  transformDocument,
7391
8180
  transformDocumentIntoPayload
7392
8181
  });
7393
- //! Replaces _.flattenDeep()
7394
8182
  //! Replaces _.get()
8183
+ //! Replaces _.flattenDeep()